Asked by:
UDP connected socket
Question
-
Hi,
We are trying to implement a UDP based server which can accept multiple clients and are using connected sockets. We start a listen socket and upon receiving a client connection, we open a new socket to serve the client and make it a connected socket (using SO_REUSEADDR). We find that the server is no longer able to accept new client connections on the listen socket until the connection being served is completed. (Tested in windows 2003 and windows XP)
You can find below sample program that illustrates this probem:
/* Tested on linux and windows
* On windows use mingw-gcc:
* gcc -Wall -g -o udplisten test.c -lws2_32
* On Linux
* gcc -Wall -g -o udplisten test.c
* Test server
* ./udplisten
* Test client with in Linux:
* echo hello | netcat -u machinename -p 5555 9898 (this goes to listen socket sockl)
* echo hello | netcat -u machinename -p 5555 9898 (this goes to new connected socket 1)
* echo hello | netcat -u machinename -p 5556 9898 (this goes to listen socket sockl)
* echo hello | netcat -u machinename -p 5556 9898 (this goes to new connected socket 2)
*/
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SOCKET int
#define INVALID_SOCKET -1
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#undef max
#define max(x,y) ((x) > (y) ? (x) : (y))
#define MAX_CLIENTS 256
fd_set read_set, temp_set;
SOCKET client_fds[256];
//SOCKET socka = INVALID_SOCKET, sockb = INVALID_SOCKET;
SOCKET sockl;
SOCKET max;
int num_clients = 0;
struct sockaddr_in addr;
static void
die(const char *str)
{
perror(str);
exit(1);
}
static SOCKET
mksocket(struct sockaddr_in *addr)
{
SOCKET sock = INVALID_SOCKET;
int opt = 1;
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
die("socket");
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)) < 0)
die("setsockopt");
if (bind(sock, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)
die("bind");
return sock;
}
static void
process_listen(SOCKET sock, const char *label)
{
char buffer[8192];
struct sockaddr_in caddr;
int count;
int ret;
SOCKET conn_sock;
socklen_t caddr_size = sizeof(caddr);
memset(&caddr, 0, caddr_size);
count = recvfrom(sock, buffer, sizeof(buffer), 0,
(struct sockaddr *)&caddr, &caddr_size);
if (count < 0) die(label);
printf("%s %d\n", label, count);
conn_sock = mksocket(&addr);
max = max(conn_sock, max);
FD_SET(conn_sock, &read_set);
client_fds[num_clients++] = conn_sock;
ret = connect(conn_sock, (const struct sockaddr *)&caddr, caddr_size);
if (ret == 0)
printf("connected to address = %s and port = %d\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
else
printf("connetc failed address = %s and port = %d\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
}
static void
process(SOCKET sock, const char *label)
{
char buffer[8192];
struct sockaddr_in caddr;
int count;
socklen_t caddr_size = sizeof(caddr);
memset(&caddr, 0, caddr_size);
count = recvfrom(sock, buffer, sizeof(buffer), 0,
(struct sockaddr *)&caddr, &caddr_size);
if (count < 0) die(label);
printf("%s : bytes %d\n", label, count);
}
int
main(int argc, char *argv[])
{
int i;
#ifdef WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2), &wsaData))
return -1;
#endif
for (i = 0; i < MAX_CLIENTS; i++)
client_fds[i] = INVALID_SOCKET;
addr.sin_family = AF_INET;
addr.sin_port = htons(9898);
addr.sin_addr.s_addr = INADDR_ANY;
sockl = mksocket(&addr);
max = sockl;
FD_ZERO(&read_set);
FD_SET(sockl, &read_set);
for (;;) {
char buf[256];
memcpy(&temp_set, &read_set, sizeof(fd_set));
if (select(max+1, &temp_set, NULL, NULL, NULL) < 0)
die("select");
if (FD_ISSET(sockl, &temp_set))
process_listen(sockl, "LISTEN");
for (i = 0; i < num_clients; i++)
{
if (FD_ISSET(client_fds[i], &temp_set))
{
sprintf(buf, "%s %d", "RECEIVED FROM CLIENT ", i);
process(client_fds[i], buf);
}
}
}
return 0;
}The desired behavior is after a connected socket is estabished all client communication must be handled by the connected socket and listen socket becomes available for a new client. This works on unix platforms and seems to be a problem on windows. (Tested in windows 2003 server and Windows XP)
We have seen the SO_REUSEADDR documentation link below:
http://msdn.microsoft.com/en-us/library/ms740621%28v=vs.85%29.aspx
The listen socket must still be able to serve new connections as we invoked connect on a new socket (not on listen socket) but this does not seem to happen. Our sample program above uses select and we never get any trigger on the listen socket for new connections.
Thanks,
-Yogi
Tuesday, July 19, 2011 8:12 PM