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 sourceSocketHelper?pp sourceSocketUDP 8hpp sourceSocketTCP 8hpp sourceSockets 8hpp sourceSocketHelper 8hpp sourcesource30function socket fd issetMatrix3?pp sourceSocketClientThread?pp sourcearm biquad ?scade ?1 ?st q31? sourcearm conv ?2? sourcearm mat mult q15? sourcefunction socket selectResource 8inl sourcearm fir lattice init q31? sourcewięcej podobnych podstron