28 #include <SFML/Network/SocketTCP.hpp> 29 #include <SFML/Network/IPAddress.hpp> 30 #include <SFML/Network/Packet.hpp> 31 #include <SFML/Network/SocketHelper.hpp> 38 #pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro 63 myIsBlocking = Blocking;
78 memset(SockAddr.sin_zero, 0,
sizeof(SockAddr.sin_zero));
79 SockAddr.sin_addr.s_addr = inet_addr(HostAddress.
ToString().c_str());
80 SockAddr.sin_family = AF_INET;
81 SockAddr.sin_port = htons(Port);
87 if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr),
sizeof(SockAddr)) == -1)
101 bool IsBlocking = myIsBlocking;
108 if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr),
sizeof(SockAddr)) >= 0)
122 if (Status == Socket::NotReady)
131 Time.tv_sec =
static_cast<long>(Timeout);
132 Time.tv_usec = (
static_cast<long>(Timeout * 1000) % 1000) * 1000;
135 if (select(static_cast<int>(mySocket + 1), NULL, &
Selector, NULL, &Time) > 0)
139 SocketHelper::LengthType Size =
sizeof(SockAddr);
140 if (getpeername(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), &Size) != -1)
143 Status = Socket::Done;
176 sockaddr_in SockAddr;
177 memset(SockAddr.sin_zero, 0,
sizeof(SockAddr.sin_zero));
178 SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
179 SockAddr.sin_family = AF_INET;
180 SockAddr.sin_port = htons(Port);
183 if (bind(mySocket, reinterpret_cast<sockaddr*>(&SockAddr),
sizeof(SockAddr)) == -1)
186 std::cerr <<
"Failed to bind socket to port " << Port << std::endl;
191 if (listen(mySocket, 0) == -1)
194 std::cerr <<
"Failed to listen to port " << Port << std::endl;
209 sockaddr_in ClientAddress;
210 SocketHelper::LengthType Length =
sizeof(ClientAddress);
213 Connected = accept(mySocket, reinterpret_cast<sockaddr*>(&ClientAddress), &Length);
226 *Address =
IPAddress(inet_ntoa(ClientAddress.sin_addr));
239 return Socket::Error;
246 int SizeToSend =
static_cast<int>(Size);
247 for (
int Length = 0; Length < SizeToSend; Length += Sent)
250 Sent = send(mySocket, Data + Length, SizeToSend - Length, 0);
262 std::cerr <<
"Cannot send data over the network (invalid parameters)" << std::endl;
263 return Socket::Error;
279 return Socket::Error;
285 int Received = recv(mySocket, Data, static_cast<int>(MaxSize), 0);
290 SizeReceived =
static_cast<std::size_t
>(Received);
293 else if (Received == 0)
295 return Socket::Disconnected;
305 std::cerr <<
"Cannot receive data from the network (invalid parameters)" << std::endl;
306 return Socket::Error;
317 std::size_t DataSize = 0;
318 const char* Data = PacketToSend.OnSend(DataSize);
321 Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
322 Send(reinterpret_cast<const char*>(&PacketSize),
sizeof(PacketSize));
327 return Send(Data, DataSize);
343 Uint32 PacketSize = 0;
344 std::size_t Received = 0;
345 if (myPendingPacketSize < 0)
349 while (myPendingHeaderSize <
sizeof(myPendingHeader))
351 char* Data =
reinterpret_cast<char*
>(&myPendingHeader) + myPendingHeaderSize;
352 Socket::Status Status =
Receive(Data,
sizeof(myPendingHeader) - myPendingHeaderSize, Received);
353 myPendingHeaderSize += Received;
355 if (Status != Socket::Done)
359 PacketSize = ntohl(myPendingHeader);
360 myPendingHeaderSize = 0;
365 PacketSize = myPendingPacketSize;
370 while (myPendingPacket.size() < PacketSize)
373 std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()),
sizeof(Buffer));
374 Socket::Status Status =
Receive(Buffer, SizeToGet, Received);
375 if (Status != Socket::Done)
378 if (Status == Socket::NotReady)
379 myPendingPacketSize = PacketSize;
386 myPendingPacket.resize(myPendingPacket.size() + Received);
387 char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
388 memcpy(Begin, Buffer, Received);
393 PacketToReceive.
Clear();
394 if (!myPendingPacket.empty())
395 PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
396 myPendingPacket.clear();
397 myPendingPacketSize = -1;
412 std::cerr <<
"Failed to close socket" << std::endl;
440 return mySocket == Other.mySocket;
449 return mySocket != Other.mySocket;
460 return mySocket < Other.mySocket;
477 void SocketTCP::Create(SocketHelper::SocketType Descriptor)
480 mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_STREAM, 0);
484 myPendingHeaderSize = 0;
485 myPendingPacket.clear();
486 myPendingPacketSize = -1;
493 if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes),
sizeof(Yes)) == -1)
495 std::cerr <<
"Failed to set socket option \"SO_REUSEADDR\" ; " 496 <<
"binding to a same port may fail if too fast" << std::endl;
500 if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&Yes),
sizeof(Yes)) == -1)
502 std::cerr <<
"Failed to set socket option \"TCP_NODELAY\" ; " 503 <<
"all your TCP packets will be buffered" << std::endl;
void SetBlocking(bool Blocking)
Change the blocking state of the socket.
static Socket::Status GetErrorStatus()
Get the last socket error status.
bool IsValid() const
Check if the socket is in a valid state ; this function can be called any time to check if the socket...
bool operator==(const SocketTCP &Other) const
Comparison operator ==.
Packet wraps data to send / to receive through the network.
bool operator!=(const SocketTCP &Other) const
Comparison operator !=.
Socket::Status Receive(char *Data, std::size_t MaxSize, std::size_t &SizeReceived)
Receive an array of bytes from the host (must be connected first).
Socket::Status Send(const char *Data, std::size_t Size)
Send an array of bytes to the host (must be connected first)
SocketTCP()
Default constructor.
Socket::Status Accept(SocketTCP &Connected, IPAddress *Address=NULL)
Wait for a connection (must be listening to a port).
bool Listen(unsigned short Port)
Listen to a specified port for incoming data or connections.
Socket::Status Connect(unsigned short Port, const IPAddress &HostAddress, float Timeout=0.f)
Connect to another computer on a specified port.
static SocketType InvalidSocket()
Return the value of the invalid socket.
std::string ToString() const
Get a string representation of the address.
void Clear()
Clear the packet data.
IPAddress provides easy manipulation of IP v4 addresses.
Selector allow reading from multiple sockets without blocking.
SocketTCP wraps a socket using TCP protocol to send data safely (but a bit slower) ...
static void SetBlocking(SocketType Socket, bool Block)
Set a socket as blocking or non-blocking.
bool Close()
Close the socket.
static bool Close(SocketType Socket)
Close / destroy a socket.
bool operator<(const SocketTCP &Other) const
Comparison operator <.