I want to make a server software similar to Apache on windows platforms.
. The client sends data to the specified server port and the server responds accordingly. In order to improve the client access speed, I want to use "select" to improve the performance of the server, but there are many problems in the use process.
Here is my code;
Function "create_server"
This function is used to create the server Socket and set it to non-blocking.
int create_server(char*ip_address,int port) {
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if(WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
int server_socket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
int ret = -1;
struct sockaddr_in addr;
if (server_socket == -1) {
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.S_un.S_addr= INADDR_ANY;
ret = bind(server_socket,(LPSOCKADDR)&addr,sizeof(addr));
if (ret == -1) {
perror("bind error!");
return -2;
}
listen(server_socket,5);
SetBlock(server_socket, 0);
return server_socket;}
Function "SetBlock"
This function is used to change the socket blocking mode.
int SetBlock(int sock, int isblock){
int re = 0;
unsigned long ul = 0;
if (!isblock) ul = 1;
re = ioctlsocket(sock, FIONBIO, (unsigned long*)& ul);
if (re != 0) return 0;
return 1;
}
Function "main"
int main() {
int s = create_server("127.0.0.1",6666);
int client_socket = -1;
struct sockaddr_in clientaddr;
int addrlen = sizeof(clientaddr);
char buf[1025];
int buffersize=1,result=0;
int isread = 0;
fd_set server;
struct timeval timeout;
int fd = 0;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
FD_ZERO(&server);
FD_SET(s, &server);
while (1) {
result = select(FD_SETSIZE, &server, NULL, NULL, NULL);
if (result < 1) {
perror("error!");
exit(1);
}
if (FD_ISSET(s, &server)) {
//if server can be readable and written do this
client_socket = accept(s, (struct sockaddr*) & clientaddr, &addrlen);
while (buffersize > 0) {
buffersize = recv(client_socket, buf, 1024, 0);
buf[buffersize] = '\0';
printf("%s", buf);
if (buffersize < 1024) {
break;
}
}
buffersize = 1;
}
}
return 0;}
As you know, TCP takes some time to establish a connection. I want to use the "select" function to reduce the setup time of multi-client connections. I think the function "accept" is the process of establishing connection between client and server, but how to use IO multiplexing in this process, please help me.
the use of select() will delay all client connections to the server.
suggest a sequence similar to:
create a thread pool
create a sockaddr_in
sock_t serverSock = socket()
bind()
listen()
while( 1 )
{
sock_t clientSock = accept( serverSock, ... )
pass clientSock to available thread and mark thread as 'busy'
}
That way, the communication with a client does not 'hang' on a select(), nor a accept()
in each thread:
while(1)
{
wait until thread marked as 'busy'
sock_t mySocket = passedSocket
perform all communication with the specific client
close( mySocket );
mark thread as 'idle'
}
Related
I am building a client-server program in C using sockets. Both my client and my server use a fixed number of threads to operate. I tested with very few client and server threads at first (5 and 3) and everything seemed to work fine. But now I tried to up the number of client threads to 500 (while the number of server thread stays at 3), but everything breaks. The first hundred or so client can send their request and receive a response, but the others don't receive anything from the server.
I'm working on a Debian Windows Subsystem if that changes anything.
I have also tried upping the number of server thread to 300 but the problem still happens.
Here is my (very) simplified code.
Client thread
int client_socket= socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(2018);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
memset(&addr.sin_zero, 0, sizeof(addr.sin_zero));
connect(client_socket, (struct sockaddr *) &addr, sizeof(addr));
int response;
int cid = 1;
send(client_socket, &cid, sizeof(int), 0);
int len = read_socket(socket, &response, sizeof(int), 1000);
if (len == 0) {
printf("No response");
} else {
printf("Response");
}
close(client_socket);
Server thread
int socket_fd, cid, len;
while (1)
{
socket_fd =
accept(socket_fd, (struct sockaddr *)&thread_addr, &socket_len);
if (socket_fd> 0) {
int cid;
int len = read_socket(socket_fd, &cid, sizeof(cid), 1000);
if (len == 0) {
printf("Nothing");
}
send(socket_fd, &cid, sizeof(int),0);
close(socket_fd);
}
}
And here is my helper function read_socket()
ssize_t read_socket(int sockfd, void *buf, size_t obj_sz, int timeout) {
int ret;
int len = 0;
struct pollfd fds[1];
fds->fd = sockfd;
fds->events = POLLIN;
fds->revents = 0;
do {
// wait for data or timeout
ret = poll(fds, 1, timeout);
if (ret > 0) {
if (fds->revents & POLLIN) {
ret = recv(sockfd, (char*)buf + len, obj_sz - len, 0);
if (ret < 0) {
// abort connection
perror("recv()");
return -1;
}
len += ret;
}
} else {
// TCP error or timeout
if (ret < 0) {
perror("poll()");
}
break;
}
} while (ret != 0 && len < obj_sz);
return ret;
}
Like I said, some client can complete their execution with no problem, but a lot of them don't receive a response from the server.
I am new in Unix/Linux networking programming, so I have written server-client program in below.In this code there is one socket between client and server, client requests to server, then server responses from 1 to 100 numbers to client. So my question is how can we do this process with 3 socket( tcp connection) without using thread? ( e.g. First socket runs then second runs then third runs then first again. ) Do you have any suggestion?
Client.c
int main()
{
int sock;
struct sockaddr_in sa;
int ret;
char buf[1024];
int x;
sock = socket (AF_INET, SOCK_STREAM, 0);
bzero (&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(SERVER_PORT);
inet_pton (AF_INET, SERVER_IP, &sa.sin_addr);
ret = connect (sock,
(const struct sockaddr *) &sa,sizeof (sa));
if (ret != 0) {
printf ("connect failed\n");
exit (0);
}
x = 0;
while (x != -1) {
read (sock, buf , sizeof(int));
x = ntohl(*((int *)buf));
if (x != -1)
printf ("int rcvd = %d\n", x);
}
close (sock);
exit (0);
}
Server.c
int main()
{
int list_sock;
int conn_sock;
struct sockaddr_in sa, ca;
socklen_t ca_len;
char buf[1024];
int i;
char ipaddrstr[IPSTRLEN];
list_sock = socket (AF_INET, SOCK_STREAM, 0);
bzero (&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(SERVER_PORT);
bind (list_sock,(struct sockaddr *) &sa,sizeof(sa));
listen (list_sock, 5);
while (1){
bzero (&ca, sizeof(ca));
ca_len = sizeof(ca); // important to initialize
conn_sock = accept (list_sock,(struct sockaddr *) &ca,&ca_len);
printf ("connection from: ip=%s port=%d \n",inet_ntop(AF_INET, &(ca.sin_addr),
ipaddrstr, IPSTRLEN),ntohs(ca.sin_port));
for (i=0; i<100; ++i){
*((int *)buf) = htonl(i+20);
// we using converting to network byte order
write (conn_sock, buf, sizeof(int));
}
* ((int *)buf) = htonl(-1);
write (conn_sock, buf, sizeof(int));
close (conn_sock);
printf ("server closed connection to client\n");
}
}
I think it best to look at the excellent resource Beej's Guide to Netwokr Programming which goes into detail about this. He also has some good examples which you can use as a starting point and he covers all the major platforms including windows.
Basically you do:
socket()
bind()
listen()
accept()
accept() returns a socket connected to a unique client. Then you'd use select, poll or epoll to determine when data is available on those sockets. I suggest you can look at the man pages for these API's and Beej's guide. It's where I first learned network programming.
Looking at your code, your inner loop is wrong. When you accept a connection, you need to add it to a list or something. Currently, you overwrite it and loose it. You should use (e)poll or select to tell you which has data. You can write to any of them at any time. Again, look at the examples in Beej's guide, they are most helpful.
Maybe it's not exactly what you want,but I think you could try epoll,There is a simple example
typedef struct event_loop
{
int max_event;
int epfd;
}event_loop;
event_loop* create_event_loop()
{
event_loop *ep = malloc(sizeof(event_loop));
ep->max_event = 512;
ep->epfd = epoll_create(512);
return ep;
}
int add_event(event_loop *ep, int fd)
{
epoll_event ee;
ee.data.fd = fd;
ee.event = EPOLLIN | EPOLLPRI;
epoll_ctl(ep->epfd, EPOLL_CTL_ADD, fd, &ee);
}
void event_main(event_loop *ep, int listenfd)
{
epoll_event events[512];
int nfds, i, newfd;
while(1)
{
if(nfds = epoll_wait(ep->epfd, events, 512, -1) == -1)
exit(1);
for(i = 0; i < nfds; i++)
{
if(events[nfds].data.fd == listenfd)
{
newfd = accept(listenfd, NULL, NULL);
add_event(ep, newfd);
}
else
{
//do what you want
}
}
}
}
epoll is a high-efficiency solution,just man epoll get more information
/* SEND FUNC. */
int mysend(unsigned char *buffer, int len) {
int sock,ret;
int status,flags;
struct sockaddr_in6 servaddr;
int opt = 1;
char *addr = "1101::1";
sock = socket(AF_INET6,SOCK_DGRAM,0);
if (sock < 0)
return -1;
if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )
return -1;
flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags|O_NONBLOCK);
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(61616);
status = inet_pton(AF_INET6, addr, &servaddr.sin6_addr);
if (status <= 0) {
perror("inet_pton");
return -1;
}
/* send message to server */
status = sendto(sock, buffer, len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (status < 0) {
perror("sendto");
return -1;
}
close(sock);
printf("MESSAGE SENT SUCCESSFULLY\n");
return 0;
}
/* RECEIVE FUNC. */
int myrcv() {
int sock,ret;
int status,len,rx_bytes;
int timeout,nfds =1;
struct sockaddr_in6 servaddr;
struct timeval wait;
unsigned char rxbuff[1024];
char *rcv;
char *addr = "1101::1";
fd_set rd;
struct pollfd *fds;
sock = socket(AF_INET6,SOCK_DGRAM,0);
if (sock < 0)
return -1;
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(61616);
status = inet_pton(AF_INET6, addr, &servaddr.sin6_addr);
if (status <= 0)
return -1;
bind(sock,(struct sockaddr *)&servaddr,sizeof(servaddr));
timeout = (1* 1000);
wait.tv_sec = 10;
wait.tv_usec = 0;
len = sizeof(servaddr);
fds->fd = sock;
fds->events = POLLIN;
for(;;) {
//FD_ZERO(&rd);
//FD_SET(sock,&rd);
printf("Waiting for data....\n");
ret = poll(fds,nfds,timeout);
//ret = select(1,&rd,NULL,NULL,&wait);
if(ret < 0)
break;
if(fds->revents == 0)
printf("revents 0 %d\n",ret);
if(ret == 0)
continue;
memset(rxbuff,0,1024);
//if(FD_ISSET(sock,&rd)) {
printf("receiving message\n");
rx_bytes = recvfrom(sock,rxbuff,1024,0,(struct sockaddr *)&servaddr,&len);
memcpy(rcv,rxbuff,rx_bytes);
//}
}
close(sock);
return 0;
}
int main()
{
/* call mysend() periodically using sigaction() */
/* create a thread that continuously monitors(calls myrcv()) for incoming data */
return 0;
}
I'm unable to receive the packets from the server, but I could see the packets in the tcpdump output. Above are the sample client code snippets, which tries to receive and send the data from/to the server. The scenario is: the client needs to send data periodically to server and should also be able to receive any data from the server.
I have tried using both poll and select methods but failed to receive. Please let me know if I'm missing anything. Thanks for your support.
The problem you have with receiving is that you need to bind the receiving socket to the local port.
You also have other things that can be improved, like creating a single socket for both sending and receiving and using SO_REUSEADDR on the sending socket (not needed on a write-only socket).
What you should do is:
Create socket
Set socket options
Bind to local address (Use IN6ADDR_ANY_INIT to bind to all interfaces)
Write to server
Poll for reply
Several things:
Your receive function (myrcv) isn't specifying a listen port via the bind() call. That's the most likely problem. Ditto for your send function, although a port is chosen randomly for you.
In you myrcv() function, I don't see where you have actually initialized fds or nfsd prior to calling poll().
Re-opening and closing the socket on each call to mysend() looks problematic. If you are expecting the server to send back to the same client on the same port it received the message on, chances are high you have already closed the socket. You should just open one socket for both sending and receiving. You can share the same socket between your send thread and your receive thread.
I have writter code snippet for UDP Client and server. I am using same port for sending and receiving. My problem is that there are many messages drops at client side, so can someone help me to optimize my code, here is my code for UDP client:
#define SERVERIP "192.168.170.155"
#define SERVERPORT 5000
#define DEVICE_SEND_PORT 5000
#define DEVICE_RECEIVE_PORT 5000
#define BUFFERSIZE 2048
/**For socket file descriptor identification*/
#define S1READY 0x01
int m_SendSocketId;
int m_ReceiveSocketId;
int msgcount;
int socketbuffsize = 1*1024*1024;
/**
* FUNCTION NAME : waitToRead
* Implementation of select and non-blocking socket mechanism
* #param socket Socket that needs to be in select and non blocking mode
* #return Returnd the file descriptors which, returned by select function
*/
int waitToRead(int socket)
{
fd_set fds;
struct timeval timeout;
int rc; // number of file descriptor returned
int result; // result
int fd; // file descriptor
fd=fcntl(socket,F_GETFL,0);
fcntl(socket,F_SETFL,fd | O_NONBLOCK);
// Set time limit.
timeout.tv_sec = 1;
timeout.tv_usec = 0;
// Create a descriptor containing our sockets.
FD_ZERO(&fds);
FD_SET(socket, &fds);
rc = select(sizeof(fds)*8, &fds, NULL, NULL, &timeout);
if (rc==-1)
{
printf("[%s:%d#%s] Select Failed\n",__FILE__, __LINE__,__func__);
return -1;
}
result = 0;
if (rc > 0)
{
if (FD_ISSET(socket, &fds))
result |= S1READY;
}
return result;
}
/**
* FUNCTION NAME : receiveMessage
* This function opens particular port that is defined in the
* Configuration file, and listens on that port.
* #return if there'll be any issue in listening, then it will return
* false otherwise it will return true.
*/
bool receiveMessage()
{
struct sockaddr_in serverAddr; //Information about the Device UDP Server
struct sockaddr_in client_addr; // Information about Qgate Server
char buffer[BUFFERSIZE]; // Buffer to store incoming message
int addr_len; // to store client address length
int serverlen; // to store server address length
int sockResult; // to store result given by waitToRead
int optval = 1;
int receivedByte = 0;
//Open a datagram Socket
if((m_ReceiveSocketId = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("[%s:%d#%s] UDP Client - socket() error\n",__FILE__, __LINE__,__func__);
return false;
}
//Configure Server Address.
//set family and port
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(DEVICE_RECEIVE_PORT);
setsockopt(m_ReceiveSocketId, SOL_SOCKET,SO_REUSEADDR, &optval, sizeof(optval));
/*if (setsockopt(m_ReceiveSocketId, SOL_SOCKET, SO_RCVBUF, &socketbuffsize, sizeof(socketbuffsize)) == -1)
{
printf("Recieve Socket memory Allocation fail\n");
}*/
if((serverAddr.sin_addr.s_addr = INADDR_ANY) == (unsigned long)INADDR_NONE)
{
printf("[%s:%d#%s] Host Not found(%d)\n",__FILE__, __LINE__,__func__,h_errno);
close(m_ReceiveSocketId); // close the socket
return false;
}
if (bind(m_ReceiveSocketId, (struct sockaddr *) &serverAddr,sizeof(struct sockaddr_in)) < 0 )
{
printf("[%s:%d#%s] UDP Client- Socket Bind error=%s\n",__FILE__, __LINE__,__func__,strerror(errno));
close(m_ReceiveSocketId); // close the socket
return false;
}
serverlen = (int )sizeof(serverAddr);
addr_len = sizeof(struct sockaddr);
// Loop and listen for incoming message
while(1)
{
//wait at select to, read
sockResult = waitToRead(m_ReceiveSocketId);
if(sockResult == S1READY)
{
receivedByte = read(m_ReceiveSocketId,buffer,BUFFERSIZE);
buffer[receivedByte] = '\0';
if(receivedByte == -1)
{
printf("[%s:%d#%s] UDP Client - receive error", __FILE__,__LINE__,__func__);
close(m_ReceiveSocketId);
return false;
}
else if(receivedByte > 0)
{
//printf("[%s:%d#%s] received message = %d bytes\n",__FILE__,__LINE__,__func__,(int)strlen(buffer));
printf("count: %d, buffer %s \n", msgcount++, buffer);
}
}
memset(buffer, 0, BUFFERSIZE);
fflush(stdout);
}
close(m_ReceiveSocketId); // close the socket
printf("[%s:%d#%s] Recieve socket closed:%s\n",
__FILE__, __LINE__,__func__, strerror(errno));
return true;
}
bool sendMessage(char *message)
{
struct sockaddr_in serverAddr; //Information about the server
struct sockaddr_in deviceAddr; //Device UDP Client Address for sending message
int optval = 1;
//Open a datagram Socket
if((m_SendSocketId = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("[%s:%d#%s] UDP Client - socket() error\n",__FILE__, __LINE__,__func__);
return false;
}
// Clear out the device struct
memset(&deviceAddr, 0x00, sizeof(struct sockaddr_in));
deviceAddr.sin_family = AF_INET;
deviceAddr.sin_port = htons(DEVICE_SEND_PORT);
setsockopt(m_SendSocketId, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
/*if (setsockopt(m_SendSocketId, SOL_SOCKET, SO_SNDBUF, &socketbuffsize, sizeof(socketbuffsize)) == -1)
{
printf("send Socket memory Allocation fail\n");
}*/
if((deviceAddr.sin_addr.s_addr = INADDR_ANY) == (unsigned long)INADDR_NONE)
{
// in netdb.h
printf("[%s:%d#%s] Host Not found(%d)\n",__FILE__, __LINE__,__func__, h_errno);
close(m_SendSocketId); // close the socket
return false;
}
if (bind(m_SendSocketId, (struct sockaddr *) &deviceAddr,sizeof(struct sockaddr_in)) < 0 )
{
printf("[%s:%d#%s] UDP Client- Socket Bind error=%s\n",__FILE__, __LINE__,__func__,strerror(errno));
close(m_SendSocketId); // close the socket
return false;
}
// Clear out the server struct
memset(&serverAddr, 0x00, sizeof(struct sockaddr_in));
//Configure Server Address.
//set family and port
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVERPORT);
//serverAddr.sin_addr.s_addr = htonl(39898);
if((serverAddr.sin_addr.s_addr = inet_addr(SERVERIP)) == (unsigned long)INADDR_NONE)
{
printf("[%s:%d#%s] Host Not found %d\n",__FILE__, __LINE__,__func__,h_errno);
close(m_SendSocketId);
return false;
}
// Send data to the server.
if( sendto(m_SendSocketId, message,strlen(message) ,0, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0 )
{
printf("[%s:%d#%s] UDP Client - sendto() error=%s \n",__FILE__, __LINE__,__func__,strerror(errno));
close(m_SendSocketId);
return false;
}
close(m_SendSocketId);
return true;
}
int main ()
{
int loop;
char str[10];
msgcount = 1;
pthread_t receiveThread;
if(pthread_create(&receiveThread, NULL,(void *)&receiveMessage, NULL) != 0)
{
printf("[%s:%d#%s] thread create Failed(%s)\n",
__FILE__, __LINE__,__func__, strerror(errno));
return false;
}
for(loop =0; loop < 1000; loop++)
{
sprintf(str,"%4d",loop);
sendMessage(str);
}
pthread_join(receiveThread, NULL);
return 0;
}
Here is the temporary UDP server code, it receives almost above 90% messages and also sends the same, but udpclient is not able to receive the messages.
int main()
{
int sock;
int addr_len, bytes_read, bytes_send;
char recv_data[1024];
int i;
int count=0;
struct sockaddr_in server_addr , client_addr;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5000);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
//client_addr.sin_family = AF_INET;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if (bind(sock,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1)
{
perror("Bind");
exit(1);
}
addr_len = sizeof(struct sockaddr);
printf("\nUDPServer Waiting for client on port 5000");
fflush(stdout);
while (1)
{
bytes_read = recvfrom(sock,recv_data,1024,0,(struct sockaddr *)&client_addr, (socklen_t *)&addr_len);
recv_data[bytes_read] = '\0';
if(recv_data[0]!=0x07)
{
recv_data[0] = 0x09;
//client_addr.sin_port = htons(51254);
bytes_send = sendto(sock, recv_data, bytes_read, 0, (struct sockaddr *)&client_addr, (socklen_t)sizeof(client_addr));
if(bytes_send < 0 )
{
perror("send to ");
}
printf("\nNumber %d", ++count);
memset(&recv_data, 0x00, 1024);
}
else
{
printf("Received Keep ALive\n");
}
memset(&client_addr, 0x00, sizeof(struct sockaddr_in));
fflush(stdout);
}
return 0;
}
Any help would be highly appreciated.
Thanks Yuvi
Your code has nothing to do with UDP dropping packets, except possibly that you are sending packets too fast for the network or the receiver. UDP isn't reliable. It drops packets. If your application protocol requires no dropped packets, you have to build in reliability at that level, via an ACK-based or NACK-based protocol with retries.
Or use TCP like everybody else does in this situation.
The problem was in sendMessage Function, here I was recreating socket every time when I need to send message, and I think that takes time. I don't know yet which is calls are blocking but making sending socket resolves my problem. Now the dropping of message is upto 20 to 30 % only.
I m writing a chat application (client & server) using C in VS 2010.
I have finished writing my code as you can see below but there is still a problem.
This problem is that the client doesn't receive on time the messages that server sends.
Server code :
#include <WinSock2.h>
#include <stdio.h>
#include <time.h>
main()
{
SOCKET ListeningSocket;
SOCKET AcceptSocket;
SOCKADDR_IN ServerAddr;
SOCKADDR_IN ClientAddr;
WSADATA wsaData;
const unsigned short PORT = 4444;
FD_SET fdread;
FD_SET BackUpfdread;
FD_SET fdwrite;
FD_SET BackUpfdwrite;
int maxDescriptor;
SOCKET SocketArray[20];
int index = 0;
int selectResults;
int i,k;
int clientAddrSize;
int RecvBytes;
int SentBytes;
char SentBuff[500];
char RecvBuff[500];
struct timeval timeout;
// Initialize Winsock2.2
WSAStartup(MAKEWORD(2,2),&wsaData);
// Initialize Listening Socket
ListeningSocket = socket(AF_INET,SOCK_STREAM,0);
// Initialize ServerAddr
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
ServerAddr.sin_port = htons(PORT);
// Bind the ServerAddr with ListeningSocket
bind(ListeningSocket,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr));
// Listening Socket
listen(ListeningSocket,5);
FD_ZERO(&fdread);
FD_ZERO(&BackUpfdread);
FD_ZERO(&fdwrite);
FD_ZERO(&BackUpfdwrite);
// Asign ListeningSocket at fdread
FD_SET(ListeningSocket,&fdread);
maxDescriptor = ListeningSocket;
SocketArray[index] = ListeningSocket;
index++;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
// Main loop starts here
for(; ;)
{
BackUpfdread = fdread;
BackUpfdwrite = fdwrite;
selectResults = select(maxDescriptor+1,&BackUpfdread,&BackUpfdwrite,NULL,&timeout);
//printf("server select() OK\n");
if(selectResults == -1)
{
printf("Select() error");
WSACleanup();
return 0;
}
for(i=0;i<=index-1;i++)
{
//printf("%d\n",SocketArray[i]);
if(FD_ISSET(SocketArray[i],&BackUpfdread))
{
if(SocketArray[i] == ListeningSocket) // we have a new connection
{
clientAddrSize = sizeof(ClientAddr);
AcceptSocket = accept(ListeningSocket,(SOCKADDR *)&ClientAddr,&clientAddrSize);
// Add the newest accepted socket to the fdread and fdwrite sets.
FD_SET(AcceptSocket,&fdread);
FD_SET(AcceptSocket,&fdwrite);
// Add the newest accepted socket into SocketArray
SocketArray[index] = AcceptSocket;
index++;
// keep track of the maxDescriptor.
if(AcceptSocket > maxDescriptor)
{
maxDescriptor = AcceptSocket;
}
printf("New connection from %s on socket %d\n", inet_ntoa(ClientAddr.sin_addr), AcceptSocket);
}else{ // That means that the socket is not from a new conection and has something sent.
memset(RecvBuff,0,sizeof(RecvBuff));
RecvBytes = recv(SocketArray[i], RecvBuff, sizeof(RecvBuff)-1, 0);
if(RecvBytes > 0) // Some data received.
{
printf("Message Sent.\n");
printf("Message was: %s\n",RecvBuff);
for(k=0;k<=index-1;k++)
{
if(SocketArray[k] != ListeningSocket && SocketArray[k] != SocketArray[i])
{
memset(SentBuff,0,sizeof(SentBuff));
strcpy(SentBuff,RecvBuff);
SentBytes = send(SocketArray[k],SentBuff,sizeof(SentBuff),0);
if(SentBytes > 0)
{
printf("Message Forwarded\n");
}else{
printf("Message forward error\n");
}
}
}
}
}
}
}
SleepEx(10, FALSE);
}// Main loop ends here
}
Client code :
#include <WinSock2.h>
#include <stdio.h>
#include <time.h>
main()
{
SOCKET ConnectSocket;
SOCKET SocketArray[20];
SOCKADDR_IN ServerAddr;
WSADATA wsaData;
FD_SET fdwrite;
FD_SET fdread;
FD_SET BackUpfdread;
FD_SET BackUpfdwrite;
char server_address[20] = "192.168.1.4";
char SentBuff[500];
char RecvBuff[500];
const unsigned short PORT = 4444;
int maxDescriptor;
int index = 0;
int SelectResults;
int i;
int RecvBytes;
int SentBytes;
BOOL bOpt = TRUE;
struct timeval timeout;
// Initialize Winsock 2.2
WSAStartup(MAKEWORD(2,2),&wsaData);
// Initialize ServerAddr
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = inet_addr(server_address);
ServerAddr.sin_port = htons(PORT);
// Create a new socket to make a client connection.
ConnectSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
setsockopt(ConnectSocket, IPPROTO_TCP, TCP_NODELAY,(char*)&bOpt,sizeof(BOOL));
// Clear the fd sets
FD_ZERO(&fdread);
FD_ZERO(&BackUpfdread);
FD_ZERO(&fdwrite);
FD_ZERO(&BackUpfdwrite);
// Asign ConnectSocket into fdread and fdwrite.
FD_SET(ConnectSocket,&fdread);
FD_SET(ConnectSocket,&fdwrite);
// Set timer
timeout.tv_sec = 0;
timeout.tv_usec = 0;
maxDescriptor = ConnectSocket;
SocketArray[index] = ConnectSocket;
index++;
// Make a connection to the server with socket s.
if(connect(ConnectSocket, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
{
printf("Couldn't connect to the server\n");
}
// Main loop starts here
for(; ;)
{
BackUpfdread = fdread;
BackUpfdwrite = fdwrite;
memset(SentBuff, 0, sizeof(SentBuff));
printf("Write: ");
gets_s(SentBuff, sizeof(SentBuff));
SelectResults = select(maxDescriptor+1,&BackUpfdread,&BackUpfdwrite,NULL,&timeout);
for(i=0;i<=index-1;i++)
{
// Something to read from server.
if(FD_ISSET(SocketArray[i],&BackUpfdread) && SocketArray[i] == ConnectSocket)
{
RecvBytes = recv(SocketArray[i], RecvBuff, sizeof(RecvBuff), 0);
if(RecvBytes > 0)
{
printf("%s\n",RecvBuff);
// Cleaning the Receive Buffer
memset(RecvBuff,0,sizeof(RecvBuff));
}
}
// Something to write.
if(FD_ISSET(SocketArray[i],&BackUpfdwrite) && SocketArray[i] == ConnectSocket)
{
SentBytes = send(SocketArray[i], SentBuff,sizeof(SentBuff),0);
// Cleaning the Sent Buffer
memset(SentBuff,0,sizeof(SentBuff));
}
}
SleepEx(10, FALSE);
} // Main menu ends here
}
In my opinion something seems not working good at clients side. I m telling this because if i use telnet application as client messages transferred correct.
Does anyone have an idea on how to fix this ?
Thanks
Just a wild guess: As you are using a hard coded ip-address:port tuple to access the server, are you sure it is the correct on?
Client 2 does not "... have to write something ..." to receive, but is blocked in gets_s() waiting for user input, and therefore cannot select() and therefore cannot recv().
To solve this blocking issue you can go for two approaches.
1 Mulit-threaded solution (more portable)
Change the client design to handle the server connection (writing to it and reading form it) asynchronously, for example in a different thread then the main thread.
2 Single-threaded solution (non-portable)
2.1 Windows
You can use ReadConsoleEvent() to implement non-blocking read from the console.
For example this could be done like this:
/*
* Does a non-blocking read of characters from the stdin into the
* buffer referenced by 'pszBuffer' up to a maximum of 'sizeBuffer'.
*
* If bEcho is TRUE the characters read are echoed to the console window.
*
* Returns the characters read or a negative value on error.
*/
DWORD ReadConsoleNonBlocking(char * pszBuffer, size_t sizeBuffer, BOOL bEcho)
{
DWORD dwRC = 0;
static HANDLE stdinHandle = 0;
stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
{
if (!pszBuffer)
return -1;
if (!sizeBuffer)
return -2;
{
INPUT_RECORD input = {0};
DWORD NumberOfEventsRead = 0;
if (!ReadConsoleInput(stdinHandle, &input, 1, &NumberOfEventsRead))
return -3;
if (NumberOfEventsRead && (KEY_EVENT == input.EventType) && input.Event.KeyEvent.bKeyDown)
{
DWORD dwCharactersRead = 0;
while (input.Event.KeyEvent.wRepeatCount > dwCharactersRead && dwCharactersRead < sizeBuffer)
{
pszBuffer[dwCharactersRead] = input.Event.KeyEvent.uChar.AsciiChar;
if ('\r' == pszBuffer[dwCharactersRead])
pszBuffer[dwCharactersRead] = '\n';
if (bEcho)
printf("%c", pszBuffer[dwCharactersRead]); /* echo character read to console */
++ dwCharactersRead;
}
dwRC = dwCharactersRead;
}
}
}
return dwRC;
}
2.2 UNIX
You can use the result of fileno(stdin) to retrieve the file descriptor for standard input and add it to the set of file descriptors passed to select() to be notified if something was entered via the console.