C++ windows socket UDP packet loss - c++

I have a 10g NIC and a UDP stream of data about 3.8Gb/s. When I send packets (from another process) I lose packets on the receive side.
My CPU is at +/- 20% and the card is connected to a x8 PCIe. Jumbo packets set to 9014 Bytes (the UDP stream is very big). SO_RCVBUF set to 1073741824 (less then this number I get packet loss) and BUFLEN is 8192.
Receive function:
char buf[BUFLEN];
while (1)
{
fflush(stdout);
memset(buf, '\0', BUFLEN);
if ((recv_len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == SOCKET_ERROR)
{
printf(" recvfrom() failed with error code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
...Parsing packet...
}
Set socket function:
void set_sock(SOCKET *s, struct sockaddr_in *server, struct sockaddr_in *si_other)
{
int slen, recv_len;
char buf[BUFLEN];
WSADATA wsa;
slen = sizeof(si_other);
//Initialise winsock
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
printf("Failed.Error Code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
if (LOBYTE(wsa.wVersion) != 2 || HIBYTE(wsa.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
exit(EXIT_FAILURE);
}
else
printf("The Winsock 2.2 dll was found okay\n");
//Create a socket
if ((*s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
printf(" Could not create socket : %d", WSAGetLastError());
}
printf(" Socket created.\n");
//Prepare the sockaddr_in structure
server->sin_family = AF_INET;
server->sin_addr.s_addr = INADDR_ANY;
server->sin_port = htons(PORT);
int res;
int bufferSize = 1073741824;
int bufferSizeLen = sizeof(bufferSize);
res = setsockopt(*s, SOL_SOCKET, SO_RCVBUF, (char *)&bufferSize, bufferSizeLen);
if (res == SOCKET_ERROR) {
printf("setsockopt for failed with error: %u\n", WSAGetLastError());
}
else
printf("Set SO_RCVBUF buffer: %d\n", bufferSize);
// If iMode != 0, non-blocking mode is enabled.
u_long iMode = 0;
res = ioctlsocket(*s, FIONBIO, &iMode);
if (res != NO_ERROR)
{
printf("ioctlsocket failed with error: %ld\n", res);
}
//Bind
if (bind(*s, (struct sockaddr *)server, sizeof(*server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
else
{
puts("Bind done\n");
}
}
What else can I configure or do to prevent the packet loss when transmitting packets?

Related

Winsock2, client-server communication - send/recv in turns

I want to write a client/server application, in which client and server can exchange messages.
Client site communication:
send
recv
send
recv
Server site communication:
recv
send
recv
send
However, I have a problem, because only one message is send/recv. After that, the socket is closed and further messages are not being sent. Whats wrong and how to fix this? Thank you.
Server code:
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_PORT "27501"
#define SIZE 1024
int SendAllToClient(SOCKET ClientSocket, char *buffer)
{
int iSendResult;
int total = 0, len = 1024;
int bytesleft = 1024;
while( total < len )
{
iSendResult = send( ClientSocket, buffer, 1024, NULL);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
total += iSendResult;
bytesleft -= iSendResult;
}
printf("Bytes sent: %d\n", iSendResult);
return total<len?- 1: 1;
}
char *ReadFromClient(SOCKET ConnectSocket)
{
int iResult;
char *buffer = new char[1024];
memset(buffer, 0, 1024);
do
{
iResult = recv(ConnectSocket, buffer, 1024, 0);
if ( iResult > 0 )
printf("Bytes received: %d\n", iResult);
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
}
while( iResult > 0 );
return buffer;
}
int main(int argc , char *argv[])
{
WSADATA wsaData;
char *buffer;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int sessionID;
int iResult;
// Datagram d1,d2,d3;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 )
{
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET)
{
printf("socket failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR)
{
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf("Server is listening on localhost:%s ...\n", DEFAULT_PORT);
// Accept a client socket
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
ClientSocket = accept(ListenSocket, (SOCKADDR*)&addr, &addrlen);
if (ClientSocket == INVALID_SOCKET)
{
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
char *ip = inet_ntoa(addr.sin_addr);
int port = addr.sin_port;
printf("\nClient %s:%d connected to server\n", ip, port);
// No longer need server socket
closesocket(ListenSocket);
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR)
{
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
//read
buffer = ReadFromClient(ClientSocket);
printf("FROM CLIENT: %s\n", buffer);
//send
memset(buffer, 0, 1024);
memcpy(buffer, "Hi client, how are you?", strlen("Hi client, how are you?"));
SendAllToClient(ClientSocket, buffer);
//read
//send
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
Client code:
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_PORT "27501"
#define SIZE 1024
int SendAllToServer(SOCKET ServerSocket, char *buffer)
{
int iSendResult;
int total = 0, len = 1024;
int bytesleft = 1024;
while( total < len )
{
iSendResult = send( ServerSocket, buffer, 1024, NULL);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ServerSocket);
WSACleanup();
return 1;
}
total += iSendResult;
bytesleft -= iSendResult;
}
printf("Bytes sent: %d\n", iSendResult);
return total<len?- 1: 1;
}
char *ReadFromServer(SOCKET ConnectSocket)
{
int iResult;
char *buffer = new char[1024];
memset(buffer, 0, 1024);
do {
iResult = recv(ConnectSocket, buffer, 1024, 0);
if ( iResult > 0 )
printf("Bytes received: %d\n", iResult);
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
} while( iResult > 0 );
return buffer;
}
int main(int argc , char *argv[])
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char* buffer;
int sessionID;
int iResult;
// Datagram d1,d2;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
//send
buffer = new char[1024];
memset(buffer, 0, 1024);
memcpy(buffer, "Hi server", strlen("Hi server"));
SendAllToServer(ConnectSocket, buffer);
//read
memset(buffer, 0, 1024);
buffer = ReadFromServer(ConnectSocket);
printf("FROM SERVER: %s\n", buffer);
//send
//read
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
EDIT
Server
#include "data_types.h"
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <iostream>
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_PORT "27015"
#define SIZE 1024
int SendAllToClient(SOCKET ClientSocket)
{
char *buffer = new char[SIZE];
int iSendResult;
memset(buffer, 0, SIZE);
int total = 0, len = SIZE;
int bytesleft = SIZE;
while( total < len )
{
iSendResult = send( ClientSocket, buffer + total, bytesleft, NULL);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
total += iSendResult;
bytesleft -= iSendResult;
}
printf("Bytes sent: %d\n", iSendResult);
delete buffer;
return total<len?- 1: 1;
}
char* ReadFromClient(SOCKET ClientSocket)
{
std::string data = "";
char *all = NULL;
char buffer[1];
int total = 0, len = SIZE;
int bytesleft = SIZE;
int iResult;
memset(buffer, 0, 1);
while(total < len)
{
if ((iResult = recv(ClientSocket, buffer, 1, 0)) == 0)
{
if (errno != 0)
{
// cleanup
closesocket(ClientSocket);
WSACleanup();
exit(1);
}
}
data = data + std::string(buffer);
total += iResult;
bytesleft -= iResult;
memset(buffer, 0, 1);
}
all = new char[data.length() + 1];
strcpy(all, data.c_str());
return all;
}
int main(int argc , char *argv[])
{
WSADATA wsaData;
char *buffer;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int sessionID;
int iResult;
// Datagram d1,d2,d3;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 )
{
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET)
{
printf("socket failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR)
{
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf("Server is listening on localhost:%s ...\n", DEFAULT_PORT);
// Accept a client socket
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
ClientSocket = accept(ListenSocket, (SOCKADDR*)&addr, &addrlen);
if (ClientSocket == INVALID_SOCKET)
{
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
char *ip = inet_ntoa(addr.sin_addr);
int port = addr.sin_port;
printf("\nClient %s:%d connected to server\n", ip, port);
// No longer need server socket
closesocket(ListenSocket);
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR)
{
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
//read
buffer = new char[1024];
memset(buffer, 0, 1024);
buffer = ReadFromClient(ClientSocket);
printf("FROM CLIENT: %s\n", buffer);
//send
memset(buffer, 0, 1024);
memcpy(buffer, "Hi client, how are you?", strlen("Hi client, how are you?"));
// Send an initial buffer
iResult = send( ClientSocket, buffer, (int)strlen(buffer), 0 );
if (iResult == SOCKET_ERROR) {
wprintf(L"send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
//read
//send
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
Client
#include "data_types.h"
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <iostream>
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_PORT "27015"
#define SIZE 1024
int SendAllToServer(SOCKET ClientSocket)
{
char *buffer = new char[SIZE];
memset(buffer, 0, SIZE);
int total = 0, len = SIZE;
int bytesleft = SIZE, iSendResult;
while( total < len )
{
iSendResult = send( ClientSocket, buffer + total, bytesleft, NULL);
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
total += iSendResult;
bytesleft -= iSendResult;
}
printf("Bytes sent: %d\n", iSendResult);
delete buffer;
return total<len?- 1: 1;
}
char *ReadFromServer(SOCKET ClientSocket)
{
std::string data = "";
char *all = NULL;
char buffer[1];
int total = 0, len = SIZE;
int bytesleft = SIZE;
int iResult;
memset(buffer, 0, 1);
while(total < len)
{
if ((iResult = recv(ClientSocket, buffer, 1, 0)) == 0)
{
if (errno != 0)
{
// cleanup
closesocket(ClientSocket);
WSACleanup();
exit(1);
}
}
data = data + std::string(buffer);
total += iResult;
bytesleft -= iResult;
memset(buffer, 0, 1);
}
all = new char[data.length() + 1];
strcpy(all, data.c_str());
return all;
}
int main(int argc , char *argv[])
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char* buffer;
int sessionID;
int iResult;
// Datagram d1,d2;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
//send
buffer = new char[1024];
memset(buffer, 0, 1024);
memcpy(buffer, "Hi server, how are you?", strlen("Hi server, how are you?"));
// Send an initial buffer
iResult = send( ConnectSocket, buffer, (int)strlen(buffer), 0 );
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
//read
memset(buffer, 0, 1024);
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, buffer, 1024, 0);
if ( iResult > 0 )
wprintf(L"Bytes received: %d\n", iResult);
else if ( iResult == 0 )
wprintf(L"Connection closed\n");
else
wprintf(L"recv failed with error: %d\n", WSAGetLastError());
} while( iResult > 0 );
printf("FROM SERVER: %s\n", buffer);
//send
//read
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
First issue:
iSendResult = send( ClientSocket, buffer, 1024, NULL);
That 1024 should be bytesleft. If you've already read 512 bytes, you don't want to read more than another 512.
That buffer should be buffer + total. If you've already sent 512 bytes, you don't want to send the same 512 bytes again, you want to send the other 512 bytes.
Second issue:
Your ReadFromServer function is just completely broken and doesn't follow the right logic. It only returns on a fatal error and doesn't even try to read exactly 1,024 bytes. It just reads up to 1,024 bytes and then, no matter how many bytes it actually read, tries to read 1,024 bytes again -- and at the same address overwriting whatever part of the message it already read!
It should work just like the send function, first trying to receive 1,024 bytes and looping if it receives less than that until it has either received exactly 1,024 bytes or gotten a fatal error.
Third issue:
buffer = ReadFromServer(ConnectSocket);
printf("FROM SERVER: %s\n", buffer);
Don't do this. Suppose the server is malicious and sent you 1,024 bytes that are not a legal C-style string. Passing that to printf through %s could cause the client to crash or misbehave. Always treat data received from the network as untrusted and potentially hostile. Though your code will work without fixing this, one day doing this will bite you in some awful way and it's not a good habit to get into.
You should also delete[] the buffer when you're done with it. But why would you return a raw pointer anyway? You could return a std::string, a std::vector, or many other much better mechanisms that avoid the risk of leaks and make copies safe.
In fact you are closing the listen socket, so once there is an accepted connection it won't accept any more:
ClientSocket = accept(ListenSocket, (SOCKADDR*)&addr, &addrlen);
if (ClientSocket == INVALID_SOCKET)
{
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
char *ip = inet_ntoa(addr.sin_addr);
int port = addr.sin_port;
printf("\nClient %s:%d connected to server\n", ip, port);
// No longer need server socket
closesocket(ListenSocket);
Closing the listener prevents further connections.
Also, you are closing the client socket before handling it:
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR)
{
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
//read
buffer = new char[1024];
memset(buffer, 0, 1024);
buffer = ReadFromClient(ClientSocket);
printf("FROM CLIENT: %s\n", buffer);
//send
memset(buffer, 0, 1024);
memcpy(buffer, "Hi client, how are you?", strlen("Hi client, how are you?"));
// Send an initial buffer
iResult = send( ClientSocket, buffer, (int)strlen(buffer), 0 );
If you want to send and receive several times, you should read/write in a loop. You are doing that only once (and doing it incorrectly): so only one message as you describe in your question.

Can't receive UNICAST packet over WiFi using INADDR_ANY

I have a device broadcasting over ethernet, using the code below this successfully receives the packets. The device also unicasts the same packet over WiFi but this is not received (Disabling all other interfaces except WiFi in windows I get a timeout error). If I change:
address.sin_addr.s_addr = htonl(INADDR_ANY);
to
address.sin_addr.s_addr = inet_addr("192.168.0.13");
Which is the address of the wifi interface it does receive the packets. The packets over both ethernet and WiFi can be seen in WireShark, the only difference between them are the destination addresses (broadcast and unicast) and the ttl.
Here is the code:
int main()
{
int iResult;
char recv_buf[4000];
int opt = 1;
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
printf("WSAStartup failed with error: %d\n", err);
return 1;
}
SOCKET handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
int return_code = 0;
return_code = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&opt), sizeof(opt));
std::cout<<"socket option 1 return:" << return_code << std::endl;
DWORD tv = 100;
return_code = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char *>(&tv), sizeof(tv));
std::cout << "socket option 2 return:" << return_code<< std::endl;
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(3000);
address.sin_addr.s_addr = htonl(INADDR_ANY);
//address.sin_addr.s_addr = inet_addr("192.168.0.13"); //this works
memset(&address.sin_zero, 0, sizeof(address.sin_zero));
std::cout << "bind return:" << bind(handle, (const sockaddr *)&address, sizeof(sockaddr_in)) << std::endl;
// Receive data until the server closes the connection
do {
Sleep(5000);
iResult = recv(handle, recv_buf, 4000, 0);
if (iResult > 0)
printf("Bytes received: %d\n", iResult);
else if (iResult == 0)
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
} while (true);
return 0;
}

send() or recv() not syncing up

I've been doing the Winsock tutorials and following it exactly. I can't seem to get either send() or recv() to function properly. I have a basic Server and Client program set up, and the connection is being made, but the Server isn't sending a message to the Client. Using the Telnet client also doesn't receive a response from the server. I'm not really sure what's happening, and all the questions I looked at were not basic or had stuff I couldn't really understand what they were doing.
Server.cpp
#include<WinSock2.h>
#include <io.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib") //winsock library
int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s, new_socket;
sockaddr_in server, client;
int c;
char *message;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
return 1;
}
else
printf("Initialised.\n");
//create a socket
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
return 2;
}
else
printf("Socket created.\n");
//prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.S_un.S_addr = INADDR_ANY;
server.sin_port = htons(8888);
//bind the socket
if (bind(s, (sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : &d", WSAGetLastError());
return 3;
}
else
puts("Bind done");
//listen
listen(s, 3);
//accept an incoming connection
puts("Waiting for incoming connections...");
c = sizeof(sockaddr_in);
while (new_socket = accept(s, (sockaddr *)&client, &c) != INVALID_SOCKET)
{
printf("Connect successful...\n");
//reply to the client
message = "Hello Client, I have recieved your connection, but I have to go now, bye!\n";
send(new_socket, message, strlen(message), 0);
puts("Message sent.\n");
}
if (new_socket == INVALID_SOCKET)
{
printf("accept() failed with error code : %d", WSAGetLastError());
return 4;
}
//close the socket
closesocket(s);
WSACleanup();
return 0;
}
Client.cpp
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <IPHlpApi.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
int main(int argc, char *argv[])
{
//intialize variables
WSADATA wsa;
char ip[100] = "192.168.1.117";
SOCKET s;
sockaddr_in server;
char *message, server_reply[75];
int recv_size;
//initialize Winsock
printf("\nInitialising Winsock...\n");
if(WSAStartup(MAKEWORD(2,2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//create the socket
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
return 3;
}
printf("Socket created.\n");
server.sin_addr.S_un.S_addr = inet_addr(ip);
server.sin_family = AF_INET;
server.sin_port = htons(8888);
//connect to the server
if (connect(s, (sockaddr *)&server, sizeof(server)) < 0)
{
puts("connect error");
return 4;
}
else
{
printf("Connect successful");
recv_size = recv(s, server_reply, 75, 0);
}
if (recv_size <= 0)
{
puts("recv() failed\n");
}
else
{
//add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] = '\0';
puts(server_reply);
}
getchar();
//close the socket
closesocket(s);
WSACleanup();
return 0;
}
The client also fails to print the "recv() failed" line; it's like it's stuck at the recv() call.
On the server side:
you are not checking the return value of listen() for error.
you are not resetting c on each call to accept(), and you are not calling closesocket() on each client that is accepted.
you are not checking the return value of send() for error.
Try this instead:
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib") //winsock library
int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s, new_socket;
sockaddr_in server, client;
int c, res, messagelen;
const char *message;
printf("\nInitializing Winsock...");
res = WSAStartup(MAKEWORD(2,2), &wsa);
if (res != 0)
{
printf("Failed. Error: %d\n", res);
return 1;
}
printf("Initialized.\n");
//create a socket
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Could not create socket. Error: %d\n", WSAGetLastError());
return 2;
}
printf("Socket created.\n");
//prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.S_un.S_addr = INADDR_ANY;
server.sin_port = htons(8888);
//bind the socket
if (bind(s, (sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed. Error: &d", WSAGetLastError());
return 3;
}
printf("Bind done.\n");
//listen
if (listen(s, 3) == SOCKET_ERROR)
{
printf("Listen failed. Error: &d", WSAGetLastError());
return 4;
}
printf("Listening.\n");
//accept incoming connections
printf("Waiting for incoming connections...\n");
do
{
c = sizeof(sockaddr_in);
new_socket = accept(s, (sockaddr *)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("Failed to accept a client. Error: %d\n", WSAGetLastError());
return 5;
}
printf("Client connected...\n");
//reply to the client
message = "Hello Client, I have received your connection, but I have to go now, bye!\n";
messagelen = strlen(message);
do
{
res = send(new_socket, message, messagelen, 0);
if (res == SOCKET_ERROR)
{
printf("Failed to send message. Error: %d\n", WSAGetLastError());
break;
}
message += res;
messagelen -= res;
}
while (messagelen > 0);
if (messagelen == 0)
printf("Message sent.\n");
//close the client socket
closesocket(new_socket);
}
while (true);
//close the server socket
closesocket(s);
WSACleanup();
return 0;
}
On the client side, the only real problem I see is your recv() call has a potential buffer overflow waiting to happen, since you ask it to read 75 bytes, and that is the exact size of your buffer. It just happens that your server is only sending 74 bytes max, but if it ever sent more, you could overflow the buffer when appending the '\0' terminator to it.
So, either:
call recv() with sizeof(server_reply)-1 as the buffer size, to give yourself room for the added terminator:
recv_size = recv(s, server_reply, sizeof(server_reply)-1, 0);
use printf() instead of puts() so you don't need to null-terminate the buffer at all when printing it to the console. You can pass recv_size as a parameter to limit the amount of text being printed:
//server_reply[recv_size] = '\0';
//puts(server_reply);
printf("%.*s", recv_size, server_reply);
From the MSDN documentation on closesocket():
Note To assure that all data is sent and received on a connection, an application should call shutdown before calling closesocket (see Graceful shutdown, linger options, and socket closure for more information). Also note, an FD_CLOSE network event is not posted after closesocket is called.
Basically the data you have sent was still pending when you closed the socket.

C++ cant receive UDP-Packets (Socket)

I am working on a C++ UDP program, that sends a string to another client and should receive an answer.
Sending works fine, but i cant receive any packets. I looked with wireshark and my computer receives the packet at the right port and from the right IP, but my program seems to ignore them.
Do you have any idea?
int startWinsock(void);
int main()
{
long receive;
SOCKET sock;
char buffer[256];
SOCKADDR_IN si_me;
SOCKADDR_IN si_other;
///////////// Start Winsock ///////////////
receive = startWinsock();
if (receive != 0)
{
printf("Error: startWinsock, error code: %d\n", receive);
return 1;
}
else
{
printf("Winsock started!\n");
}
//////////// Create UDP Socket //////////////
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET)
{
printf("Fehler: Socket could not be created, errorcode: %d\n", WSAGetLastError());
return 1;
}
else
{
printf("UDP Socket created!\n");
}
si_me.sin_family = AF_INET;
si_me.sin_port = htons(1198);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
si_other.sin_family = AF_INET;
si_other.sin_port = htons(2000);
si_other.sin_addr.s_addr = inet_addr("10.2.134.10");
receive = connect(sock, (SOCKADDR*)&si_other, sizeof(SOCKADDR));
if (receive == SOCKET_ERROR)
{
cout << "Error : Connection Failed, Errorcode: " << WSAGetLastError() << endl;
}
else
{
cout << "Connected to" << si_other.sin_addr.s_addr << endl;
}
static int timeout = 500;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
// char broadcast = 1;
// setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
while (1)
{
printf("Insert Text: ");
gets(buffer);
//rc = sendto(s, buf, strlen(buf), 0, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN));
receive = send(sock, buffer, strlen(buffer), 0);
if (receive == SOCKET_ERROR)
{
//printf("error: sendto, error code: %d\n",WSAGetLastError());
printf("Error: send, error code: %d\n", WSAGetLastError());
//return 1;
}
else
{
printf("%d bytes sent!\n", receive);
}
static int timeout = 500;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
int wait = 0;
while (wait == 0)
{
//rc = recvfrom(s, buf, 256, 0, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN));
receive = recv(sock, buffer, sizeof(buffer), 0);
if (receive == SOCKET_ERROR)
{
//printf("Fehler: recvfrom, fehler code: %d\n",WSAGetLastError());
printf("Fehler: recv, fehler code: %d\n", WSAGetLastError());
//return 1;
}
else
{
wait = 1;
printf("%d bytes received!\n", receive);
buffer[receive] = '\0';
printf("Received: %s\n", buffer);
}
}
}
getchar();
return 0;
}
int startWinsock(void)
{
WSADATA wsa;
return WSAStartup(MAKEWORD(2, 0), &wsa);
}
To make it so your code works nearly as-is by sending to itself, do the following:
change the "me" port to match "other"... si_me.sin_port = htons( 2000 );
bind to it... bind( sock, (SOCKADDR*)&si_me, sizeof( SOCKADDR ) ); just before connect
As UDP is Datagram-Oriented and connectionless, you need to use recvfrom/sento instead of recv/send. Also the receivetimeout should be set with at timeval.
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));

recv (winsock) function hangs, though data is available

I am using winsock socket api to send a udp packet with a very high port number, which I expect to be unused at the destination. My intention is to receive back one icmp packet with destination unreachable/port unreachable message. I have created two sockets, one on which I am sending UDP packet and other socket on which I am expecting the icmp packet. The send is successful. The destination returns the ICMP reply as well, this I can verify on wireshark. Now when I do a recv, to receive data, the recv function hangs. My objective is to read the data from recv function, which does not happen.
Any help for understaning/fixing this behavior will be highly appreciated. Thanks in advance.
I am attaching the code snippets here...
void sendPacket(unsigned int socketFd, char *packet, char* remoteIP, char* pingType)
{
int nsent = -1;
int rc = -1;
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(struct addrinfo));
if (strcasecmp(pingType, "UDP")==0)
{
hints.ai_flags = AI_CANONNAME; /* always return canonical name */
hints.ai_family = AF_INET; /* 0, AF_INET, AF_INET6, etc. */
hints.ai_socktype = SOCK_DGRAM; /* 0, SOCK_STREAM, SOCK_DGRAM, etc. */
}
rc = getaddrinfo(remoteIP, NULL, &hints, &res);
if ( rc != 0)
{
printf("... Function: %s\tError setting remote address. Exiting. ... \n", __FUNCTION__);
exit(-1);
}
if (strcasecmp(pingType, "UDP")==0)
{
((struct sockaddr_in *)res->ai_addr)->sin_port = htons(34344);
strcpy(packet, "TIMESTAMP");
}
do
{
if (strcasecmp(pingType, "UDP")==0)
{
nsent=sendto(socketFd, packet, strlen(packet), 0, (struct sockaddr *)res->ai_addr, (socklen_t)res->ai_addrlen);
if (nsent < 0)
{
continue;
}
}
}while(nsent < 0);
return;
}
double receivePacket(int socketFd, struct timeval* tvSend, pingReply** lastReplyNode, char* pingType)
{
ssize_t nRecv = -1;
double rc = -1;
char recvbuf[1024];
do
{
nRecv = recv(socketFd, (char *)recvbuf, 1024, 0);
}
while(nRecv < 0);
if (nRecv < 0)
{
return -1;
}
rc = processPacket(recvbuf, nRecv, tvSend, lastReplyNode, pingType);
if (rc == -1)
{
printf("... Function: %s\tReceiving error in Data/Protocol ...\n", __FUNCTION__);
return -1;
}
return rc;
}
void createSocket(unsigned int *sendSocketFd, unsigned int *receiveSocketFd, char *pingType)
{
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
exit(-1);
}
#endif
#ifdef _WIN32
if (strcasecmp(pingType, "UDP")==0)
{
int rc = -1;
struct sockaddr_in src_address;
unsigned long int length;
int optval = 1;
DWORD Length;
OSVERSIONINFO g_OSVersionInfo;
BOOLEAN g_IsWindowsLonghorn = TRUE;
BOOLEAN g_UseFtosToSetTos = TRUE;
int ret, iVal=0;
unsigned int sz = sizeof(iVal);
g_OSVersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO);
GetVersionEx( &g_OSVersionInfo );
if( g_OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
{
if( g_OSVersionInfo.dwMajorVersion >= 6 )
{
g_IsWindowsLonghorn = TRUE;
g_UseFtosToSetTos = TRUE;
}
}
*receiveSocketFd = INVALID_SOCKET;
*receiveSocketFd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (*receiveSocketFd < 0)
{
printf("Function: %s\tReceiving Socket creation error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError());
exit(-1);
}
src_address.sin_family=AF_INET;
src_address.sin_addr.s_addr=inet_addr("x.x.x.x");
src_address.sin_port=htons(0);
rc = bind((SOCKET)*receiveSocketFd,(struct sockaddr *)&src_address,sizeof(src_address));
if (rc < 0)
{
printf("Function: %s\tReceiving Socket bind error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError());
exit(-1);
}
iVal = 30000; // in milliseconds
ret = setsockopt(*receiveSocketFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&iVal, sz);
if (ret == SOCKET_ERROR)
{
printf("%d\n", WSAGetLastError());
return; // Temporary
}
rc = WSAIoctl((SOCKET)*receiveSocketFd, SIO_RCVALL, &optval, sizeof(optval), NULL, 0, &length, NULL, NULL);
if (rc == SOCKET_ERROR)
{
printf("Function: %s\tReceiving Socket ioctl error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError());
exit(-1);
}
printf("Function: %s\treceiveSocketFd %d ...\n", __FUNCTION__, *receiveSocketFd);
}
else
{
*receiveSocketFd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (*receiveSocketFd < 0)
{
printf("Function: %s\tReceiving Socket creation error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError());
exit(-1);
}
printf("Function: %s\treceiveSocketFd %d ...\n", __FUNCTION__, *receiveSocketFd);
}
#endif
#ifndef _WIN32
unsigned int size = 1024; /* OK if setsockopt fails */
setsockopt(*receiveSocketFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
#else
char size[5] = "1024"; /* OK if setsockopt fails */
setsockopt(*receiveSocketFd, SOL_SOCKET, SO_RCVBUF, size, sizeof(size));
#endif
if (strcasecmp(pingType, "UDP")==0)
{
*sendSocketFd = socket(AF_INET, SOCK_DGRAM, 0);
if (*sendSocketFd < 0)
{
printf("Send Socket creation error.");
exit(-1);
}
printf("Function: %s\tsendSocketFd %d ...\n", __FUNCTION__, *sendSocketFd);
}
return;
}
You don't get 'destination unreachable' unless the socket is connected, in the UDP sense, and then you don't get it via recv(), you get it as an errno value from a probably subsequent send().