I need your help because I have to make two console application in C++ : a client able to send as many string as possible to a server (in order to send coordinates). I succeeded to make a blocking socket but as I have to integrate it after in a development platform (3D VIA Virtools) which call my script at each frame, I have no other solution than using asynchronous sockets.
*My problem is that I can only send string once, and after I don't receive FD_WRITE anymore...*
This begin to drive me crazy so any help will be highly appreciated (I'm a beginner in programming), thanks in advance to everyone who will feel a little bit concerned by my problem
Here is my code,
Server
#include <winsock2.h>
#include <Windows.h>
#include <conio.h>
#pragma comment(lib, "ws2_32.lib")
#define SOCKET_ERRNO WSAGetLastError()
#define ADDRESS "127.0.0.1"
#define PORT 1234
static SOCKET ListenFirstFreePort()
{
struct sockaddr_in addr;
int len = sizeof(addr);
SOCKET hSocket;
// Create socket
hSocket = socket( PF_INET, SOCK_STREAM, 0 );
if( hSocket == INVALID_SOCKET )
{
printf( "socket() error %d\n", SOCKET_ERRNO );
exit(1);
}
// Connexion setting for local connexion
addr.sin_family = AF_INET ;
addr.sin_addr.s_addr = inet_addr(ADDRESS);
addr.sin_port = htons (PORT);
// bind socket
if ( bind( hSocket, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR )
{
printf( "bind() error %d\n", SOCKET_ERRNO );
exit(1);
}
// listen
if ( listen( hSocket, 100) == SOCKET_ERROR )
{
printf( "listen() error %d\n", SOCKET_ERRNO );
exit(1);
}
return hSocket;
}
void main()
{
WSADATA stack_info;
SOCKET ahSocket[2];
WSAEVENT ahEvents[2];
DWORD dwEvent;
WSANETWORKEVENTS NetworkEvents;
int rc;
// Initialize Winsock
WSAStartup(MAKEWORD(2,0), &stack_info) ;
// Create events
ahEvents[0] = WSACreateEvent();
ahEvents[1] = WSACreateEvent();
// Create listening socket
ahSocket[0] = ListenFirstFreePort();
rc = WSAEventSelect(ahSocket[0], ahEvents[0], FD_ACCEPT );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
while (TRUE)
{
// Waiting for so;ething to happen
// Basically we'll firstly receive the connexion of the client socket
// and then we'll be notificated when there will be some data to read
// look for events
dwEvent = WSAWaitForMultipleEvents( 2, ahEvents, FALSE, WSA_INFINITE, FALSE);
switch (dwEvent)
{
case WSA_WAIT_FAILED:
printf("WSAEventSelect: %d\n", WSAGetLastError());
break;
case WAIT_IO_COMPLETION:
case WSA_WAIT_TIMEOUT:
break;
default:
//if there is one dwEvent-WSA_WAIT_EVENT_0 has to be substracted so as to dwEvent correspond to the index of the concerned socket
dwEvent -= WSA_WAIT_EVENT_0;
// enumeration of the events on the socket[dwEvent]
if (SOCKET_ERROR == WSAEnumNetworkEvents(ahSocket[dwEvent], ahEvents[dwEvent], &NetworkEvents))
{
printf("WSAEnumNetworkEvent: %d lNetworkEvent %X\n",
WSAGetLastError(), NetworkEvents.lNetworkEvents);
NetworkEvents.lNetworkEvents = 0;
}
else
{
if (FD_CLOSE & NetworkEvents.lNetworkEvents)
{
printf( "FD_CLOSE ok (dwEvent=%d)\n", dwEvent );
printf( "press a key to exit\n" );
getch(); // require conio.h
WSACloseEvent( ahEvents[0] );
WSACloseEvent( ahEvents[1] );
exit(0);
}
if (FD_READ & NetworkEvents.lNetworkEvents)
{
char szBuffer[256]; int cbRecv;
// Only the second socket expect to receive data
printf( "FD_READ ok (dwEvent=%d)\n", dwEvent );
// read data
cbRecv = recv( ahSocket[dwEvent], szBuffer, sizeof(szBuffer) - 1, 0 );
if( cbRecv <= 0 )
{
printf( "recv() error %d\n", SOCKET_ERRNO );
exit(1);
}
// On ecrit ce paquet (On remet le 0 au cas ou le paquet
// ait ete coupe en 2 - je sais, ca n'arrivera jamais en local)
// we put the 0 in case it has been cut - unlikey to happen on local network
szBuffer[cbRecv] = 0;
// write data in console window
printf( "socket %d : '%s'\n", dwEvent, szBuffer );
}
}
if (FD_ACCEPT & NetworkEvents.lNetworkEvents)
{
struct sockaddr_in addrAccept;
int lenAccept;
lenAccept = sizeof( addrAccept );
// we should have dwEvent=0
printf( "accept ok (dwEvent=%d)\n", dwEvent );
// we create another socket to accept the connexion with the client socket
ahSocket[1] = accept(ahSocket[dwEvent], (struct sockaddr *)&addrAccept, &lenAccept);
// we want to be informed on when we'll be able read data from it
rc = WSAEventSelect(ahSocket[1], ahEvents[1], FD_READ|FD_CLOSE );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
}
}
}
}
Client
#include <winsock2.h>
#include <conio.h>
#include <time.h>
#pragma comment(lib, "ws2_32.lib")
#define SOCKET_ERRNO WSAGetLastError()
#define ADDRESS "127.0.0.1"
#define PORT 1234
SOCKET ConnectToPort()
{
struct sockaddr_in addr;
SOCKET hSocket;
u_long arg; int err;
// Create socket
hSocket = socket( PF_INET, SOCK_STREAM, 0 );
if( hSocket == INVALID_SOCKET )
{
printf( "socket() error %d\n", SOCKET_ERRNO );
exit(1);
}
// Connexion setting for local connexion
addr.sin_family = AF_INET ;
addr.sin_addr.s_addr = inet_addr(ADDRESS);
addr.sin_port = htons (PORT);
// Connect
if( connect( hSocket, (struct sockaddr *)&addr, sizeof(addr) ) == SOCKET_ERROR )
{
// As we are in non-blocking mode we'll always have the error
// WSAEWOULDBLOCK whichis actually not one
if( SOCKET_ERRNO != WSAEWOULDBLOCK )
{
printf( "connect() error (%d)\n", SOCKET_ERRNO );
exit(1);
}
}
return hSocket;
}
void main()
{
int initClockTime;
WSADATA stack_info;
SOCKET ahSocket[1];
WSAEVENT ahEvents[1];
DWORD dwEvent;
WSANETWORKEVENTS NetworkEvents;
int rc;
// Initialize Winsock
WSAStartup(MAKEWORD(2,0), &stack_info) ;
// Create event
ahEvents[0] = WSACreateEvent();
// Create and connect a socket on the server socket
ahSocket[0]= ConnectToPort();
// not sure if I have to use or not
/*u_long arg = 1;
ioctlsocket( ahSocket[0] , FIONBIO, &arg );*/
// the application wants to receive notification of a completed connection
rc = WSAEventSelect(ahSocket[0], ahEvents[0], FD_CONNECT );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
while (TRUE)
{
// look for events
dwEvent = WSAWaitForMultipleEvents( 1, ahEvents, FALSE, 1000, FALSE);
switch (dwEvent)
{
case WSA_WAIT_FAILED:
printf("WSAEventSelect: %d\n", WSAGetLastError());
break;
case WAIT_IO_COMPLETION:
case WSA_WAIT_TIMEOUT:
break;
default:
printf("while\n");
//if there is one dwEvent-WSA_WAIT_EVENT_0 has to be substracted so as to dwEvent correspond to the index of the concerned socket
dwEvent -= WSA_WAIT_EVENT_0;
// enumeration of the events on the socket[dwEvent]
if (SOCKET_ERROR == WSAEnumNetworkEvents(ahSocket[dwEvent], ahEvents[dwEvent], &NetworkEvents))
{
printf("WSAEnumNetworkEvent: %d lNetworkEvent %X\n", WSAGetLastError(), NetworkEvents.lNetworkEvents);
NetworkEvents.lNetworkEvents = 0;
}
else
{
if (FD_CONNECT & NetworkEvents.lNetworkEvents)
{
//connexion is OK
printf( "FD_CONNECT ok (dwEvent=%d)\n", dwEvent );
// now that we are connected we want to send data or be aware when the other socket is disconnected
rc = WSAEventSelect(ahSocket[dwEvent], ahEvents[dwEvent], FD_CLOSE | FD_WRITE );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
}
if (FD_CLOSE & NetworkEvents.lNetworkEvents)
{
printf( "FD_CLOSE ok (dwEvent=%d)\n", dwEvent );
printf( "press a key to exit\n" );
getch();
WSACloseEvent( ahEvents[0] );
exit(0);
}
if (FD_WRITE & NetworkEvents.lNetworkEvents)
{
char szBuffer[256]; int cbBuffer;
printf( "FD_WRITE ok (dwEvent=%d)\n", dwEvent );
// create string and return the size
cbBuffer = sprintf( szBuffer, "Coucou", dwEvent );
// send the string with 0 at the end
rc = send( ahSocket[dwEvent], szBuffer, cbBuffer + 1, 0 );
if (SOCKET_ERROR == rc)
{
printf("WSAEnumNetworkEvent: %d lNetworkEvent %X\n", WSAGetLastError(), NetworkEvents.lNetworkEvents);
}
// not sure if I have to use it
//WSAResetEvent(ahEvents[0]);
}
}
}
}
}
download .cpp files : https://www.dropbox.com/s/pjuipz7v4iwr5ea/Clientserver%20TCP.zip
You are not getting FD_WRITE notifications after the first one because you are not taking into account the following paragraph from the documentation:
The FD_WRITE network event is handled slightly differently. An
FD_WRITE network event is recorded when a socket is first connected
with a call to the connect, ConnectEx, WSAConnect, WSAConnectByList,
or WSAConnectByName function or when a socket is accepted with accept,
AcceptEx, or WSAAccept function and then after a send fails with
WSAEWOULDBLOCK and buffer space becomes available. Therefore, an
application can assume that sends are possible starting from the first
FD_WRITE network event setting and lasting until a send returns
WSAEWOULDBLOCK. After such a failure the application will find out
that sends are again possible when an FD_WRITE network event is
recorded and the associated event object is set.
After your first call to send(), the socket is still writable since its outbound buffer is not full. As long as you still have data to send, keep calling send() until it reports an WSAWOULDBLOCK error indicating the buffer is full. At that point, you have to keep track of your remaining data until you get an FD_WRITE notification indicating the socket is writable again so you can continue sending your remaining data from where you left off.
I would recommend to look at regular select() for non-blocking I/O first. Here's couple of links for you to get started:
Non-blocking I/O and select() (the link is broken)
Non-Blocking Sockets in TCP/IP
Related
I am trying to implement a unit test to see if using the function "WaitForMultipleObjects" works properly with socket. To do so I implemented a simple UDP server-client protocol. The server bind his socket and wait to receive data from receiver using the function "WaitForMultipleObjects". Once the server receives data from the client, it displays it then waits 5 seconds. The problem here that if the client try to send 2 messages during this five seconds, the first one is displayed while the second one will block the function "WaitForMultipleObjects" forever. I know that I can use the "Select" function to do that since the socket is the only object I am waiting for, but it's just a unit test. In my real project I need to wait on a socket and another object's type which is a windows event (which is of type HANDLE) at the same time. And that's why i am trying to use "WaitForMultipleObjects" on sockets.
Here's the server code:
/*
Simple UDP Server
*/
#include<winsock2.h>
#include<windows.h>
#include <ws2tcpip.h>
#include<stdio.h>
#include<iostream>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to listen for incoming data
int main()
{
SOCKET s;
struct sockaddr_in server, si_other;
int slen , recv_len;
char buf[BUFLEN];
WSADATA wsa;
HANDLE SEvent;
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);
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_DGRAM , 0 )) == 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 );
//Bind
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done");
SEvent = WSACreateEvent();
WSAEventSelect( s, SEvent, FD_READ);
//keep listening for data
while(1)
{
printf("Waiting for data...");
fflush(stdout);
//clear the buffer by filling null, it might have previously received data
memset(buf,'\0', BUFLEN);
INT r = WaitForMultipleObjectsEx(1,&SEvent,FALSE,INFINITE,TRUE);
if( r == WAIT_OBJECT_0)
{
if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == SOCKET_ERROR)
{
printf("recvfrom() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
//print details of the client/peer and the data received
printf("Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));
printf("Data: %s\n" , buf);
//now reply the client with the same data
if (sendto(s, buf, recv_len, 0, (struct sockaddr*) &si_other, slen) == SOCKET_ERROR)
{
printf("sendto() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
ResetEvent(SEvent);
Sleep(5000);
}
else
{
std::cerr<<"WaitForMultipleObject() Error ( "<<GetLastError()<<" )"<<std::endl;
exit(0);
}
}
closesocket(s);
WSACleanup();
return 0;
}
Here's the client code:
/*
Simple udp client
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#define SERVER "127.0.0.1" //ip address of udp server
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to listen for incoming data
int main(void)
{
struct sockaddr_in si_other;
int s, slen=sizeof(si_other);
char buf[BUFLEN];
char message[BUFLEN];
WSADATA wsa;
//Initialise winsock
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Initialised.\n");
//create socket
if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SOCKET_ERROR)
{
printf("socket() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
//setup address structure
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
si_other.sin_addr.S_un.S_addr = inet_addr(SERVER);
//start communication
while(1)
{
printf("Enter message : ");
gets(message);
//send the message
if (sendto(s, message, strlen(message) , 0 , (struct sockaddr *) &si_other, slen) == SOCKET_ERROR)
{
printf("sendto() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
//receive a reply and print it
//clear the buffer by filling null, it might have previously received data
/*memset(buf,'\0', BUFLEN);
//try to receive some data, this is a blocking call
if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == SOCKET_ERROR)
{
printf("recvfrom() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
puts(buf);*/
}
closesocket(s);
WSACleanup();
return 0;
}
Note: I didn't write all the code. I used a code that was already written (from the internet) but made some changes.
Does anyone know how to fix this problem? (using "WaitForMultipleObjects" on socket properly)
The problem here that if the client try to send 2 messages during this five seconds, the first one is displayed while the second one will clock the function "WaitForMultipleObjects" forever.
Your server code has a race condition.
Your should call WSAResetEvent/ResetEvent before calling recvfrom, not afterwards. Otherwise, there is a possiblity that new data will arrive between the call to recvfrom and WSAResetEvent, setting the event object to signalled. In that case, WSAResetEvent will set the event back to non-signalled, causing you to lose the notification of new data being available.
Also, according to the documentation of WSAEventSelect, after reading data from a socket, if more data is available to be read, the event will automatically be set to signalled again, in order to indicate that more data is available. If you call WSAResetEvent afterwards, then you will set the event back to non-signalled, causing you to lose the notification of new data being available. This is probably the reason for the behavior you describe in the question.
You should rather call WSAResetEvent/ResetEvent immediately after WSAWaitForMultipleEvents/WaitForMultipleObjectsEx. See the documentation for the function WSAWaitForMultipleEvents for a code example (that example uses overlapped I/O instead of WSAEventSelect, though).
I am trying to configure my MOCAP node (virtual machine) IP address to match that of MOTIVE software on my PC. The MOCAP.yaml file is intially set to 224.0.0.1 but every time I change it to match the IP address of my machine it cause an EINVAL error like this:
terminate called after throwing an instance of 'SocketException'
what(): Failed to set socket option: EINVAL
=========================================================================
REQUIRED process [mocap_node-1] has died!
process has died [pid 4575, exit code -6, cmd /home/radlab/mocap/devel/lib/mocap_optitrack/mocap_node __name:=mocap_node __log:=/home/radlab/.ros/log/3fe16008-4521-11e6-9638-080027e2597b/mocap_node-1.log].
log file: /home/radlab/.ros/log/3fe16008-4521-11e6-9638-080027e2597b/mocap_node-1*.log
Initiating shutdown!
=========================================================================
Here is the code for the socket.cpp
/*
* Socket.cpp
*
* Created on: 14.11.2008
* Author:
*/
// Implementation of the Socket class.
#include "mocap_optitrack/socket.h"
#include <cstring>
#include <cerrno>
#include <fcntl.h>
#include <iostream>
#include <stdio.h>
#include <sstream>
#include <ros/ros.h>
UdpMulticastSocket::UdpMulticastSocket( const int local_port, const std::string multicast_ip )
{
// Create a UDP socket
ROS_INFO( "Creating socket..." );
m_socket = socket( AF_INET, SOCK_DGRAM, 0 );
if( m_socket < 0 )
throw SocketException( strerror( errno ) );
// Allow reuse of local addresses
ROS_INFO( "Setting socket options..." );
int option_value = 1;
int result = setsockopt( m_socket, SOL_SOCKET, SO_REUSEADDR, (void*)&option_value, sizeof( int ) );
if( result == -1 )
{
std::stringstream error;
error << "Failed to set socket option: ";
switch( errno )
{
case EBADF:
error << "EBADF";
break;
case EFAULT:
error << "EFAULT";
break;
case EINVAL:
error << "EINVAL";
break;
case ENOPROTOOPT:
error << "ENOPROTOOPT";
break;
case ENOTSOCK:
error << "ENOTSOCK";
break;
default:
error << "unknown error";
break;
}
throw SocketException( error.str().c_str() );
}
// Fill struct for local address
memset ( &m_local_addr, 0, sizeof ( m_local_addr ) );
m_local_addr.sin_family = AF_INET;
m_local_addr.sin_addr.s_addr = htonl( INADDR_ANY );
m_local_addr.sin_port = htons( local_port );
ROS_INFO( "Local address: %s:%i", inet_ntoa( m_local_addr.sin_addr ), ntohs( m_local_addr.sin_port ) );
// Bind the socket
ROS_INFO( "Binding socket to local address..." );
result = bind( m_socket, (sockaddr*)&m_local_addr, sizeof( m_local_addr ));
if( result == -1 )
{
std::stringstream error;
error << "Failed to bind socket to local address:" << strerror( errno );
throw SocketException( error.str().c_str() );
}
// Join multicast group
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr( multicast_ip.c_str() );
mreq.imr_interface = m_local_addr.sin_addr;
ROS_INFO( "Joining multicast group %s...", inet_ntoa( mreq.imr_multiaddr ) );
result = setsockopt(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
if( result == -1 )
{
std::stringstream error;
error << "Failed to set socket option: ";
switch( errno )
{
case EBADF:
error << "EBADF";
break;
case EFAULT:
error << "EFAULT";
break;
case EINVAL:
error << "EINVAL";
break;
case ENOPROTOOPT:
error << "ENOPROTOOPT";
break;
case ENOTSOCK:
error << "ENOTSOCK";
break;
default:
error << "unknown error";
break;
}
throw SocketException( error.str().c_str() );
}
// Make socket non-blocking
ROS_INFO( "Enabling non-blocking I/O" );
int flags = fcntl( m_socket, F_GETFL , 0 );
result = fcntl(m_socket, F_SETFL, flags | O_NONBLOCK);
if( result == -1 )
{
std::stringstream error;
error << "Failed to enable non-blocking I/O: " << strerror( errno );
throw SocketException( error.str().c_str() );
}
}
UdpMulticastSocket::~UdpMulticastSocket()
{
close( m_socket );
}
int UdpMulticastSocket::recv()
{
memset ( buf, 0, MAXRECV + 1 );
sockaddr_in remote_addr;
int addr_len = sizeof(struct sockaddr);
int status = recvfrom(
m_socket,
buf,
MAXRECV,
0,
(sockaddr *)&remote_addr,
(socklen_t*)&addr_len);
if( status > 0 )
ROS_DEBUG( "%4i bytes received from %s:%i", status, inet_ntoa( remote_addr.sin_addr ), ntohs( remote_addr.sin_port ) );
else if( status == 0 )
ROS_INFO( "Connection closed by peer" );
return status;
}
Can anyone help me figure out why I am getting this error when I change the IP address?
I don't know what mocap or motiv is, but I think you're trying to use a non-multicast ip-address to join to multicast group in line 79. That's propably what's passed to the function with std::string multicast_ip from the .yaml file.
See man page:
IP_ADD_MEMBERSHIP (since Linux 1.2)
Join a multicast group. Argument is an ip_mreqn structure.
struct ip_mreqn {
struct in_addr imr_multiaddr; /* IP multicast group
address */
struct in_addr imr_address; /* IP address of local
interface */
int imr_ifindex; /* interface index */
};
imr_multiaddr contains the address of the multicast group the
application wants to join or leave. It must be a valid
multicast address (or setsockopt(2) fails with the error
EINVAL). imr_address is the address of the local interface
with which the system should join the multicast group; if it
is equal to INADDR_ANY, an appropriate interface is chosen by
the system. imr_ifindex is the interface index of the
interface that should join/leave the imr_multiaddr group, or 0
to indicate any interface.
The ip_mreqn structure is available only since Linux 2.2. For
compatibility, the old ip_mreq structure (present since Linux
1.2) is still supported; it differs from ip_mreqn only by not
including the imr_ifindex field. (The kernel determines which
structure is being passed based on the size passed in optlen.)
IP_ADD_MEMBERSHIP is valid only for setsockopt(2).
I need to communicate between two systems on local server. So, I decided to use "Socket" programming in C++. For this I follow this tutorial. I make some changes according to my need like changing port no, IP etc which are working fine. Now the problem is I can send data from Server to Client but I am unable to receive any data from Client to Server.
Here is my code for Client:-
int main()
{
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
char *message , server_reply[2000];
int recv_size;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
server.sin_addr.s_addr = inet_addr("192.168.1.4");
server.sin_family = AF_INET;
server.sin_port = htons( 8888 );
//Connect to remote server
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected");
if((recv_size = recv(s , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
puts("recv failed");
}
puts("Reply received\n");
server_reply[recv_size] = '\0';
puts(server_reply);
message = "Cleint says:- I am Client";
if( send(s , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
puts("sending data complete\n");
system("pause");
return 0;
}
Here is My code for Server:-
int main()
{
WSADATA wsa;
SOCKET s , new_socket;
struct sockaddr_in server , client;
int c;
char *message , cleint_reply[2000];
int recv_size;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == 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( 8888 );
//Bind
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done");
//Listen to incoming connections
listen(s , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while( (new_socket = accept(s , (struct sockaddr *)&client, &c)) != INVALID_SOCKET )
{
puts("Connection accepted");
//Reply to the client
message = "Server sends:- I am Server\n";
send(new_socket , message , strlen(message) , 0);
while(1)
{
if((recv_size = recv(s , cleint_reply , 2000 , 0)) == SOCKET_ERROR)
{
// puts("recv failed");
}
else
puts("data received");
}
}
if (new_socket == INVALID_SOCKET)
{
printf("accept failed with error code : %d" , WSAGetLastError());
return 1;
}
closesocket(s);
WSACleanup();
return 0;
}
This is the console messages I am getting on Client:-
Initialising Winsock...
Initialised
Connected
Server sends:- I am server
Sending Data complete
Press any key to continue
And these are the messages I am getting on Server console:-
Initialising Winsock...
Socket Created
Bind Done
Waiting for incoming connections..
Connection accepted
So, please tell we why my server is not able to receive any thing...
Found the error.
Once you use accept() you have a new file descriptor which you need to use send and receive data [lets say for that specific CLIENT].
The accept() function shall extract the first connection on the queue of pending connections, create a new socket with the same socket type protocol and address family as the specified socket, and allocate a new file descriptor for that socket.
In your server when you get a new connection you correctly use new file descriptor recv_size to send data but you do not use that new connection's file descriptor to receive data.
Wrong code line
if((recv_size = recv(s , cleint_reply , 2000 , 0)) == SOCKET_ERROR)
Correction
if((recv_size = recv(new_socket , cleint_reply , 2000 , 0)) == SOCKET_ERROR)
this should work now
I'm trying to solve reading from socket timeout problem using select(). Unfortunately this function returns -1 immediatly after getting called. What might be wrong?
commStatus communicate( const char * tx, char * rx, const int bufSize , const char * inetAddr, const int port )
{
commStatus r;
if (!sockInitialised) initSock();
if (sockInitialised)
{
SOCKET s;
struct sockaddr_in server;
server.sin_addr.s_addr = inet_addr(inetAddr);
server.sin_family = AF_INET;
server.sin_port = htons( port );
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
std:stringstream d; d <<"Could not create socket : " << WSAGetLastError();
LogIt(d,Level::Error);
} else
{
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
r= commStatus::COMM_NO_TRANSMIT ;
} else
{
int l =strlen(tx)+strlen("DATA ");
char* dtx ;
dtx = (char*) calloc(sizeof(char),strlen(tx)+strlen("DATA ") + 1 );
sprintf(dtx,"DATA %s",tx);
if( send(s , dtx , strlen(dtx) , 0) < 0)
{
puts("Send failed");
r= commStatus::COMM_NO_TRANSMIT;
} else
{
int recv_size = 0;
struct timeval selTimeout;
selTimeout.tv_sec = 20; /* timeout (secs.) */
selTimeout.tv_usec = 0; /* 0 microseconds */
fd_set readSet;
FD_ZERO(&readSet);
#define STDIN_FILENO 0
FD_SET(STDIN_FILENO, &readSet);//stdin manually trigger reading
FD_SET(s, &readSet);//tcp socket
int numReady = select(s+1, &readSet, NULL, NULL, &selTimeout);
if(numReady > 0)
{
if((recv_size = recv(s , rx , bufSize ,0)) == SOCKET_ERROR)
{
r= commStatus::COMM_NO_RECEIVE;
} else
{
rx[recv_size] = '\0';
r= commStatus::COMM_OK;
}
} else r=commStatus::COMM_NO_RECEIVE;
}
free(dtx);
}
}
} else r= commStatus::COMM_NO_TRANSMIT;
return r;
}
As far as I can tell, you're trying to pass stdin to Winsock's select() function.
Unfortunately, under Windows, select() only takes socket handles, not generic file descriptors.
If you were to call WSAGetLastError(), you'd probably see that it returns WSAENOTSOCK.
Under C, you can examine the errno variable, it should tell you the specific problem that caused your error.
Alternatively, you may have the perror() function which will give you a readable version:
#include <stdio.h>
:
perror ("select");
If you're under Windows, WSAGetLastError() will serve as the errno variable, with this page giving the possibilities and explanations:
WSANOTINITIALISED - A successful WSAStartup call must occur before using this function.
WSAEFAULT - The Windows Sockets implementation was unable to allocate needed resources for its internal operations, or the readfds, writefds, exceptfds, or timeval parameters are not part of the user address space.
WSAENETDOWN - The network subsystem has failed.
WSAEINVAL - The time-out value is not valid, or all three descriptor parameters were null.
WSAEINTR - A blocking Windows Socket 1.1 call was canceled through WSACancelBlockingCall.
WSAEINPROGRESS - A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.
WSAENOTSOCK - One of the descriptor sets contains an entry that is not a socket.
I'm writing a MFC\C++ program that needs to create a UDP socket to receive datagrams on.
I am using blocking socket (for performance reasons) and have some errors (or misunderstanding) when trying to set timeout for receive calls.
When I set the receive timeout to 100mili using setsockopt() and the receive does timeout - it timeouts after about 600mili.
When I set the receive timeout to 1000mili using setsockopt() and the receive does timeout - it timeouts after about 1600mili.
Why is this ?
Am I doing something wrong ?
My code goes something like this:
WSADATA wsaData;
SOCKET ReceivingSocket;
SOCKADDR_IN ReceiverAddr;
int Port = 2345;
char ReceiveBuf[1024];
int BufLength = 1024;
SOCKADDR_IN SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
int Ret;
// 100mili timeout
int RecvTimeout = 100 ;
// Initialize Winsock version 2.2
if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
{
TRACE("ERROR: WSAStartup failed with error %d\n", Ret);
return;
}
// Create a new socket to receive datagrams
if ((ReceivingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))
== INVALID_SOCKET)
{
TRACE("ERROR: socket failed with error %d\n", WSAGetLastError());
WSACleanup();
return;
}
// receive datagrams from all interfaces using port 2345
ReceiverAddr.sin_family = AF_INET;
ReceiverAddr.sin_port = htons(Port);
ReceiverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// bind
if (bind(ReceivingSocket, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr))
== SOCKET_ERROR)
{
TRACE("ERROR: bind failed with error %d\n", WSAGetLastError());
closesocket(ReceivingSocket);
WSACleanup();
return;
}
// set receive timeout
if ( setsockopt (
ReceivingSocket,
SOL_SOCKET,
SO_RCVTIMEO,
(const char*)&RecvTimeout,
sizeof(RecvTimeout) ) == SOCKET_ERROR )
{
TRACE("Error using setsockopt\n") ;
closesocket(ReceivingSocket);
WSACleanup();
return;
}
// Receive 10 messages - here the timeout comes to life...
for(int i = 0 ; i < 10 ; i++)
{
TRACE("Before Recv, Ticks=%d\n", GetTickCount()) ;
if ((Ret = recvfrom(ReceivingSocket, ReceiveBuf, BufLength, 0,
(SOCKADDR *)&SenderAddr, &SenderAddrSize)) == SOCKET_ERROR)
{
if(WSAETIMEDOUT == WSAGetLastError())
TRACE("After Recv, Ticks=%d\n\n", GetTickCount()) ;
else
{
TRACE("ERROR: receive failed with error %d\n", WSAGetLastError());
closesocket(ReceivingSocket);
WSACleanup();
return;
}
}
}
closesocket(ReceivingSocket);
WSACleanup();
and the output I get is this:
Before Recv, Ticks=1476485406
After Recv, Ticks=1476486031
Before Recv, Ticks=1476486031
After Recv, Ticks=1476486656
Before Recv, Ticks=1476486656
After Recv, Ticks=1476487281
.
.
.
In addition, when I looked at the MSDN to find out more about SO_RCVTIMEO I noticed the following:
If a send or receive operation times out on a socket, the socket state is indeterminate, and should not be used..."
So basically using SO_RCVTIMEO seems like a bad idea if I do get timeouts.
Am I missing something ?
Use 'timeval' stuct to initialize timeout value.
struct timeval timeout;
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC; // in milli secs
timeout.tv_usec = 0;