SocketUDP 8cpp source


SFML - Simple and Fast Multimedia Library Main Page Namespaces Classes Files File List SocketUDP.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/SocketUDP.hpp> 00029 #include <SFML/Network/IPAddress.hpp> 00030 #include <SFML/Network/Packet.hpp> 00031 #include <algorithm> 00032 #include <iostream> 00033 #include <string.h> 00034 00035 00036 namespace sf 00037 { 00041 SocketUDP::SocketUDP() 00042 { 00043 Create(); 00044 } 00045 00046 00050 void SocketUDP::SetBlocking(bool Blocking) 00051 { 00052 // Make sure our socket is valid 00053 if (!IsValid()) 00054 Create(); 00055 00056 SocketHelper::SetBlocking(mySocket, Blocking); 00057 myIsBlocking = Blocking; 00058 } 00059 00060 00064 bool SocketUDP::Bind(unsigned short Port) 00065 { 00066 // Check if the socket is already bound to the specified port 00067 if (myPort != Port) 00068 { 00069 // If the socket was previously bound to another port, we need to unbind it first 00070 Unbind(); 00071 00072 if (Port != 0) 00073 { 00074 // Build an address with the specified port 00075 sockaddr_in Addr; 00076 Addr.sin_family = AF_INET; 00077 Addr.sin_port = htons(Port); 00078 Addr.sin_addr.s_addr = INADDR_ANY; 00079 memset(Addr.sin_zero, 0, sizeof(Addr.sin_zero)); 00080 00081 // Bind the socket to the port 00082 if (bind(mySocket, reinterpret_cast<sockaddr*>(&Addr), sizeof(Addr)) == -1) 00083 { 00084 std::cerr << "Failed to bind the socket to port " << Port << std::endl; 00085 myPort = 0; 00086 return false; 00087 } 00088 } 00089 00090 // Save the new port 00091 myPort = Port; 00092 } 00093 00094 return true; 00095 } 00096 00097 00101 bool SocketUDP::Unbind() 00102 { 00103 // To unbind the socket, we just recreate it 00104 if (myPort != 0) 00105 { 00106 Close(); 00107 Create(); 00108 myPort = 0; 00109 } 00110 00111 return true; 00112 } 00113 00114 00118 Socket::Status SocketUDP::Send(const char* Data, std::size_t Size, const IPAddress& Address, unsigned short Port) 00119 { 00120 // Make sure the socket is valid 00121 if (!IsValid()) 00122 Create(); 00123 00124 // Check parameters 00125 if (Data && Size) 00126 { 00127 // Build the target address 00128 sockaddr_in Target; 00129 Target.sin_family = AF_INET; 00130 Target.sin_port = htons(Port); 00131 Target.sin_addr.s_addr = inet_addr(Address.ToString().c_str()); 00132 memset(Target.sin_zero, 0, sizeof(Target.sin_zero)); 00133 00134 // Loop until every byte has been sent 00135 int Sent = 0; 00136 int SizeToSend = static_cast<int>(Size); 00137 for (int Length = 0; Length < SizeToSend; Length += Sent) 00138 { 00139 // Send a chunk of data 00140 Sent = sendto(mySocket, Data + Length, SizeToSend - Length, 0, reinterpret_cast<sockaddr*>(&Target), sizeof(Target)); 00141 00142 // Check errors 00143 if (Sent <= 0) 00144 return SocketHelper::GetErrorStatus(); 00145 } 00146 00147 return Socket::Done; 00148 } 00149 else 00150 { 00151 // Error... 00152 std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl; 00153 return Socket::Error; 00154 } 00155 } 00156 00157 00162 Socket::Status SocketUDP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived, IPAddress& Address, unsigned short& Port) 00163 { 00164 // First clear the size received 00165 SizeReceived = 0; 00166 00167 // Make sure the socket is bound to a port 00168 if (myPort == 0) 00169 { 00170 std::cerr << "Failed to receive data ; the UDP socket first needs to be bound to a port" << std::endl; 00171 return Socket::Error; 00172 } 00173 00174 // Make sure the socket is valid 00175 if (!IsValid()) 00176 Create(); 00177 00178 // Check parameters 00179 if (Data && MaxSize) 00180 { 00181 // Data that will be filled with the other computer's address 00182 sockaddr_in Sender; 00183 Sender.sin_family = AF_INET; 00184 Sender.sin_port = 0; 00185 Sender.sin_addr.s_addr = INADDR_ANY; 00186 memset(Sender.sin_zero, 0, sizeof(Sender.sin_zero)); 00187 SocketHelper::LengthType SenderSize = sizeof(Sender); 00188 00189 // Receive a chunk of bytes 00190 int Received = recvfrom(mySocket, Data, static_cast<int>(MaxSize), 0, reinterpret_cast<sockaddr*>(&Sender), &SenderSize); 00191 00192 // Check the number of bytes received 00193 if (Received > 0) 00194 { 00195 Address = IPAddress(inet_ntoa(Sender.sin_addr)); 00196 Port = ntohs(Sender.sin_port); 00197 SizeReceived = static_cast<std::size_t>(Received); 00198 return Socket::Done; 00199 } 00200 else 00201 { 00202 Address = IPAddress(); 00203 Port = 0; 00204 return Received == 0 ? Socket::Disconnected : SocketHelper::GetErrorStatus(); 00205 } 00206 } 00207 else 00208 { 00209 // Error... 00210 std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl; 00211 return Socket::Error; 00212 } 00213 } 00214 00215 00219 Socket::Status SocketUDP::Send(Packet& PacketToSend, const IPAddress& Address, unsigned short Port) 00220 { 00221 // Get the data to send from the packet 00222 std::size_t DataSize = 0; 00223 const char* Data = PacketToSend.OnSend(DataSize); 00224 00225 // Send the packet size 00226 Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize)); 00227 Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize), Address, Port); 00228 00229 // Send the packet data 00230 if (PacketSize > 0) 00231 { 00232 return Send(Data, DataSize, Address, Port); 00233 } 00234 else 00235 { 00236 return Socket::Done; 00237 } 00238 } 00239 00240 00245 Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address, unsigned short& Port) 00246 { 00247 // We start by getting the size of the incoming packet 00248 Uint32 PacketSize = 0; 00249 std::size_t Received = 0; 00250 if (myPendingPacketSize < 0) 00251 { 00252 // Loop until we've received the entire size of the packet 00253 // (even a 4 bytes variable may be received in more than one call) 00254 while (myPendingHeaderSize < sizeof(myPendingHeader)) 00255 { 00256 char* Data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize; 00257 Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received, Address, Port); 00258 myPendingHeaderSize += Received; 00259 00260 if (Status != Socket::Done) 00261 return Status; 00262 } 00263 00264 PacketSize = ntohl(myPendingHeader); 00265 myPendingHeaderSize = 0; 00266 } 00267 else 00268 { 00269 // There is a pending packet : we already know its size 00270 PacketSize = myPendingPacketSize; 00271 } 00272 00273 // Use another address instance for receiving the packet data ; 00274 // chunks of data coming from a different sender will be discarded (and lost...) 00275 IPAddress Sender; 00276 unsigned short SenderPort; 00277 00278 // Then loop until we receive all the packet data 00279 char Buffer[1024]; 00280 while (myPendingPacket.size() < PacketSize) 00281 { 00282 // Receive a chunk of data 00283 std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer)); 00284 Socket::Status Status = Receive(Buffer, SizeToGet, Received, Sender, SenderPort); 00285 if (Status != Socket::Done) 00286 { 00287 // We must save the size of the pending packet until we can receive its content 00288 if (Status == Socket::NotReady) 00289 myPendingPacketSize = PacketSize; 00290 return Status; 00291 } 00292 00293 // Append it into the packet 00294 if ((Sender == Address) && (SenderPort == Port) && (Received > 0)) 00295 { 00296 myPendingPacket.resize(myPendingPacket.size() + Received); 00297 char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received; 00298 memcpy(Begin, Buffer, Received); 00299 } 00300 } 00301 00302 // We have received all the datas : we can copy it to the user packet, and clear our internal packet 00303 PacketToReceive.Clear(); 00304 if (!myPendingPacket.empty()) 00305 PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size()); 00306 myPendingPacket.clear(); 00307 myPendingPacketSize = -1; 00308 00309 return Socket::Done; 00310 } 00311 00312 00316 bool SocketUDP::Close() 00317 { 00318 if (IsValid()) 00319 { 00320 if (!SocketHelper::Close(mySocket)) 00321 { 00322 std::cerr << "Failed to close socket" << std::endl; 00323 return false; 00324 } 00325 00326 mySocket = SocketHelper::InvalidSocket(); 00327 } 00328 00329 myPort = 0; 00330 myIsBlocking = true; 00331 00332 return true; 00333 } 00334 00335 00340 bool SocketUDP::IsValid() const 00341 { 00342 return mySocket != SocketHelper::InvalidSocket(); 00343 } 00344 00345 00349 unsigned short SocketUDP::GetPort() const 00350 { 00351 return myPort; 00352 } 00353 00354 00358 bool SocketUDP::operator ==(const SocketUDP& Other) const 00359 { 00360 return mySocket == Other.mySocket; 00361 } 00362 00363 00367 bool SocketUDP::operator !=(const SocketUDP& Other) const 00368 { 00369 return mySocket != Other.mySocket; 00370 } 00371 00372 00378 bool SocketUDP::operator <(const SocketUDP& Other) const 00379 { 00380 return mySocket < Other.mySocket; 00381 } 00382 00383 00388 SocketUDP::SocketUDP(SocketHelper::SocketType Descriptor) 00389 { 00390 Create(Descriptor); 00391 } 00392 00393 00397 void SocketUDP::Create(SocketHelper::SocketType Descriptor) 00398 { 00399 // Use the given socket descriptor, or get a new one 00400 mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_DGRAM, 0); 00401 myIsBlocking = true; 00402 00403 // Clear the last port used 00404 myPort = 0; 00405 00406 // Reset the pending packet 00407 myPendingHeaderSize = 0; 00408 myPendingPacket.clear(); 00409 myPendingPacketSize = -1; 00410 00411 // Setup default options 00412 if (IsValid()) 00413 { 00414 // To avoid the "Address already in use" error message when trying to bind to the same port 00415 int Yes = 1; 00416 if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1) 00417 { 00418 std::cerr << "Failed to set socket option \"reuse address\" ; " 00419 << "binding to a same port may fail if too fast" << std::endl; 00420 } 00421 00422 // Enable broadcast by default 00423 if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1) 00424 { 00425 std::cerr << "Failed to enable broadcast on UDP socket" << std::endl; 00426 } 00427 00428 // Set blocking by default (should always be the case anyway) 00429 SetBlocking(true); 00430 } 00431 } 00432 00433 } // namespace sf  ::  Copyright © 2007-2008 Laurent Gomila, all rights reserved  ::  Documentation generated by doxygen 1.5.2  :: 

Wyszukiwarka

Podobne podstrony:
SocketTCP?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