SocketTCP 8cpp source


SFML - Simple and Fast Multimedia Library Main Page Namespaces Classes Files File List SocketTCP.cpp00001 00002 // 00003 // SFML - Simple and Fast Multimedia Library 00004 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) 00005 // 00006 // This software is provided 'as-is', without any express or implied warranty. 00007 // In no event will the authors be held liable for any damages arising from the use of this software. 00008 // 00009 // Permission is granted to anyone to use this software for any purpose, 00010 // including commercial applications, and to alter it and redistribute it freely, 00011 // subject to the following restrictions: 00012 // 00013 // 1. The origin of this software must not be misrepresented; 00014 // you must not claim that you wrote the original software. 00015 // If you use this software in a product, an acknowledgment 00016 // in the product documentation would be appreciated but is not required. 00017 // 00018 // 2. Altered source versions must be plainly marked as such, 00019 // and must not be misrepresented as being the original software. 00020 // 00021 // 3. This notice may not be removed or altered from any source distribution. 00022 // 00024 00026 // Headers 00028 #include <SFML/Network/SocketTCP.hpp> 00029 #include <SFML/Network/IPAddress.hpp> 00030 #include <SFML/Network/Packet.hpp> 00031 #include <SFML/Network/SocketHelper.hpp> 00032 #include <algorithm> 00033 #include <iostream> 00034 #include <string.h> 00035 00036 00037 #ifdef _MSC_VER 00038 #pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro 00039 #endif 00040 00041 00042 namespace sf 00043 { 00047 SocketTCP::SocketTCP() 00048 { 00049 Create(SocketHelper::InvalidSocket()); 00050 } 00051 00052 00056 void SocketTCP::SetBlocking(bool Blocking) 00057 { 00058 // Make sure our socket is valid 00059 if (!IsValid()) 00060 Create(); 00061 00062 SocketHelper::SetBlocking(mySocket, Blocking); 00063 myIsBlocking = Blocking; 00064 } 00065 00066 00070 Socket::Status SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout) 00071 { 00072 // Make sure our socket is valid 00073 if (!IsValid()) 00074 Create(); 00075 00076 // Build the host address 00077 sockaddr_in SockAddr; 00078 memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero)); 00079 SockAddr.sin_addr.s_addr = inet_addr(HostAddress.ToString().c_str()); 00080 SockAddr.sin_family = AF_INET; 00081 SockAddr.sin_port = htons(Port); 00082 00083 if (Timeout <= 0) 00084 { 00085 // ----- We're not using a timeout : just try to connect ----- 00086 00087 if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1) 00088 { 00089 // Failed to connect 00090 return SocketHelper::GetErrorStatus(); 00091 } 00092 00093 // Connection succeeded 00094 return Socket::Done; 00095 } 00096 else 00097 { 00098 // ----- We're using a timeout : we'll need a few tricks to make it work ----- 00099 00100 // Save the previous blocking state 00101 bool IsBlocking = myIsBlocking; 00102 00103 // Switch to non-blocking to enable our connection timeout 00104 if (IsBlocking) 00105 SetBlocking(false); 00106 00107 // Try to connect to host 00108 if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) >= 0) 00109 { 00110 // We got instantly connected! (it may no happen a lot...) 00111 return Socket::Done; 00112 } 00113 00114 // Get the error status 00115 Socket::Status Status = SocketHelper::GetErrorStatus(); 00116 00117 // If we were in non-blocking mode, return immediatly 00118 if (!IsBlocking) 00119 return Status; 00120 00121 // Otherwise, wait until something happens to our socket (success, timeout or error) 00122 if (Status == Socket::NotReady) 00123 { 00124 // Setup the selector 00125 fd_set Selector; 00126 FD_ZERO(&Selector); 00127 FD_SET(mySocket, &Selector); 00128 00129 // Setup the timeout 00130 timeval Time; 00131 Time.tv_sec = static_cast<long>(Timeout); 00132 Time.tv_usec = (static_cast<long>(Timeout * 1000) % 1000) * 1000; 00133 00134 // Wait for something to write on our socket (which means that the connection request has returned) 00135 if (select(static_cast<int>(mySocket + 1), NULL, &Selector, NULL, &Time) > 0) 00136 { 00137 // At this point the connection may have been either accepted or refused. 00138 // To know whether it's a success or a failure, we try to retrieve the name of the connected peer 00139 SocketHelper::LengthType Size = sizeof(SockAddr); 00140 if (getpeername(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), &Size) != -1) 00141 { 00142 // Connection accepted 00143 Status = Socket::Done; 00144 } 00145 else 00146 { 00147 // Connection failed 00148 Status = SocketHelper::GetErrorStatus(); 00149 } 00150 } 00151 else 00152 { 00153 // Failed to connect before timeout is over 00154 Status = SocketHelper::GetErrorStatus(); 00155 } 00156 } 00157 00158 // Switch back to blocking mode 00159 SetBlocking(true); 00160 00161 return Status; 00162 } 00163 } 00164 00165 00169 bool SocketTCP::Listen(unsigned short Port) 00170 { 00171 // Make sure our socket is valid 00172 if (!IsValid()) 00173 Create(); 00174 00175 // Build the address 00176 sockaddr_in SockAddr; 00177 memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero)); 00178 SockAddr.sin_addr.s_addr = htonl(INADDR_ANY); 00179 SockAddr.sin_family = AF_INET; 00180 SockAddr.sin_port = htons(Port); 00181 00182 // Bind the socket to the specified port 00183 if (bind(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1) 00184 { 00185 // Not likely to happen, but... 00186 std::cerr << "Failed to bind socket to port " << Port << std::endl; 00187 return false; 00188 } 00189 00190 // Listen to the bound port 00191 if (listen(mySocket, 0) == -1) 00192 { 00193 // Oops, socket is deaf 00194 std::cerr << "Failed to listen to port " << Port << std::endl; 00195 return false; 00196 } 00197 00198 return true; 00199 } 00200 00201 00206 Socket::Status SocketTCP::Accept(SocketTCP& Connected, IPAddress* Address) 00207 { 00208 // Address that will be filled with client informations 00209 sockaddr_in ClientAddress; 00210 SocketHelper::LengthType Length = sizeof(ClientAddress); 00211 00212 // Accept a new connection 00213 Connected = accept(mySocket, reinterpret_cast<sockaddr*>(&ClientAddress), &Length); 00214 00215 // Check errors 00216 if (!Connected.IsValid()) 00217 { 00218 if (Address) 00219 *Address = IPAddress(); 00220 00221 return SocketHelper::GetErrorStatus(); 00222 } 00223 00224 // Fill address if requested 00225 if (Address) 00226 *Address = IPAddress(inet_ntoa(ClientAddress.sin_addr)); 00227 00228 return Socket::Done; 00229 } 00230 00231 00235 Socket::Status SocketTCP::Send(const char* Data, std::size_t Size) 00236 { 00237 // First check that socket is valid 00238 if (!IsValid()) 00239 return Socket::Error; 00240 00241 // Check parameters 00242 if (Data && Size) 00243 { 00244 // Loop until every byte has been sent 00245 int Sent = 0; 00246 int SizeToSend = static_cast<int>(Size); 00247 for (int Length = 0; Length < SizeToSend; Length += Sent) 00248 { 00249 // Send a chunk of data 00250 Sent = send(mySocket, Data + Length, SizeToSend - Length, 0); 00251 00252 // Check if an error occured 00253 if (Sent <= 0) 00254 return SocketHelper::GetErrorStatus(); 00255 } 00256 00257 return Socket::Done; 00258 } 00259 else 00260 { 00261 // Error... 00262 std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl; 00263 return Socket::Error; 00264 } 00265 } 00266 00267 00272 Socket::Status SocketTCP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived) 00273 { 00274 // First clear the size received 00275 SizeReceived = 0; 00276 00277 // Check that socket is valid 00278 if (!IsValid()) 00279 return Socket::Error; 00280 00281 // Check parameters 00282 if (Data && MaxSize) 00283 { 00284 // Receive a chunk of bytes 00285 int Received = recv(mySocket, Data, static_cast<int>(MaxSize), 0); 00286 00287 // Check the number of bytes received 00288 if (Received > 0) 00289 { 00290 SizeReceived = static_cast<std::size_t>(Received); 00291 return Socket::Done; 00292 } 00293 else if (Received == 0) 00294 { 00295 return Socket::Disconnected; 00296 } 00297 else 00298 { 00299 return SocketHelper::GetErrorStatus(); 00300 } 00301 } 00302 else 00303 { 00304 // Error... 00305 std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl; 00306 return Socket::Error; 00307 } 00308 } 00309 00310 00314 Socket::Status SocketTCP::Send(Packet& PacketToSend) 00315 { 00316 // Get the data to send from the packet 00317 std::size_t DataSize = 0; 00318 const char* Data = PacketToSend.OnSend(DataSize); 00319 00320 // Send the packet size 00321 Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize)); 00322 Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize)); 00323 00324 // Send the packet data 00325 if (PacketSize > 0) 00326 { 00327 return Send(Data, DataSize); 00328 } 00329 else 00330 { 00331 return Socket::Done; 00332 } 00333 } 00334 00335 00340 Socket::Status SocketTCP::Receive(Packet& PacketToReceive) 00341 { 00342 // We start by getting the size of the incoming packet 00343 Uint32 PacketSize = 0; 00344 std::size_t Received = 0; 00345 if (myPendingPacketSize < 0) 00346 { 00347 // Loop until we've received the entire size of the packet 00348 // (even a 4 bytes variable may be received in more than one call) 00349 while (myPendingHeaderSize < sizeof(myPendingHeader)) 00350 { 00351 char* Data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize; 00352 Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received); 00353 myPendingHeaderSize += Received; 00354 00355 if (Status != Socket::Done) 00356 return Status; 00357 } 00358 00359 PacketSize = ntohl(myPendingHeader); 00360 myPendingHeaderSize = 0; 00361 } 00362 else 00363 { 00364 // There is a pending packet : we already know its size 00365 PacketSize = myPendingPacketSize; 00366 } 00367 00368 // Then loop until we receive all the packet data 00369 char Buffer[1024]; 00370 while (myPendingPacket.size() < PacketSize) 00371 { 00372 // Receive a chunk of data 00373 std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer)); 00374 Socket::Status Status = Receive(Buffer, SizeToGet, Received); 00375 if (Status != Socket::Done) 00376 { 00377 // We must save the size of the pending packet until we can receive its content 00378 if (Status == Socket::NotReady) 00379 myPendingPacketSize = PacketSize; 00380 return Status; 00381 } 00382 00383 // Append it into the packet 00384 if (Received > 0) 00385 { 00386 myPendingPacket.resize(myPendingPacket.size() + Received); 00387 char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received; 00388 memcpy(Begin, Buffer, Received); 00389 } 00390 } 00391 00392 // We have received all the datas : we can copy it to the user packet, and clear our internal packet 00393 PacketToReceive.Clear(); 00394 if (!myPendingPacket.empty()) 00395 PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size()); 00396 myPendingPacket.clear(); 00397 myPendingPacketSize = -1; 00398 00399 return Socket::Done; 00400 } 00401 00402 00406 bool SocketTCP::Close() 00407 { 00408 if (IsValid()) 00409 { 00410 if (!SocketHelper::Close(mySocket)) 00411 { 00412 std::cerr << "Failed to close socket" << std::endl; 00413 return false; 00414 } 00415 00416 mySocket = SocketHelper::InvalidSocket(); 00417 } 00418 00419 myIsBlocking = true; 00420 00421 return true; 00422 } 00423 00424 00429 bool SocketTCP::IsValid() const 00430 { 00431 return mySocket != SocketHelper::InvalidSocket(); 00432 } 00433 00434 00438 bool SocketTCP::operator ==(const SocketTCP& Other) const 00439 { 00440 return mySocket == Other.mySocket; 00441 } 00442 00443 00447 bool SocketTCP::operator !=(const SocketTCP& Other) const 00448 { 00449 return mySocket != Other.mySocket; 00450 } 00451 00452 00458 bool SocketTCP::operator <(const SocketTCP& Other) const 00459 { 00460 return mySocket < Other.mySocket; 00461 } 00462 00463 00468 SocketTCP::SocketTCP(SocketHelper::SocketType Descriptor) 00469 { 00470 Create(Descriptor); 00471 } 00472 00473 00477 void SocketTCP::Create(SocketHelper::SocketType Descriptor) 00478 { 00479 // Use the given socket descriptor, or get a new one 00480 mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_STREAM, 0); 00481 myIsBlocking = true; 00482 00483 // Reset the pending packet 00484 myPendingHeaderSize = 0; 00485 myPendingPacket.clear(); 00486 myPendingPacketSize = -1; 00487 00488 // Setup default options 00489 if (IsValid()) 00490 { 00491 // To avoid the "Address already in use" error message when trying to bind to the same port 00492 int Yes = 1; 00493 if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1) 00494 { 00495 std::cerr << "Failed to set socket option \"SO_REUSEADDR\" ; " 00496 << "binding to a same port may fail if too fast" << std::endl; 00497 } 00498 00499 // Disable the Nagle algorithm (ie. removes buffering of TCP packets) 00500 if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1) 00501 { 00502 std::cerr << "Failed to set socket option \"TCP_NODELAY\" ; " 00503 << "all your TCP packets will be buffered" << std::endl; 00504 } 00505 00506 // Set blocking by default (should always be the case anyway) 00507 SetBlocking(true); 00508 } 00509 } 00510 00511 } // namespace sf  ::  Copyright © 2007-2008 Laurent Gomila, all rights reserved  ::  Documentation generated by doxygen 1.5.2  :: 

Wyszukiwarka

Podobne podstrony:
SocketUDP?pp source
SocketHelper?pp source
SocketUDP 8hpp source
SocketTCP 8hpp source
Sockets 8hpp source
SocketHelper 8hpp source
source30
function socket fd isset
Matrix3?pp source
SocketClient
Thread?pp source
arm biquad ?scade ?1 ?st q31? source
arm conv ?2? source
arm mat mult q15? source
function socket select
Resource 8inl source
arm fir lattice init q31? source

więcej podobnych podstron