Using select() in thread does not react os host disconnection - c

I have main server code, which uses select and waits for hosts activities.
I have also global structure, which stores all clients and theirs sockets.
//old code
Select in main thread unblocks intself when one of the hosts from clients array disconnects. Then I try to read data, and when it is 0, client is disconnected. Why select in Thread doesn't work in the same way? It works perfect when clients exchange data, but there is no reaction, when one of clients disconnects.
EDIT.
Sorry I have previously posted the code, which could not be compiled. The idea was, just to get the information if my idea of clients handling is correct and if this idea should work. I have created simple example and now it works. So, I have to review my oryginal code.
Working example:
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include <pthread.h>
#include <limits.h>
#include <errno.h>
#include <time.h>
#include <sys/wait.h>
#define MAXCLIENTS 1000
#define FRAMESIZE 40
struct Client
{
int socket;
char state;
};
struct Client clients[2];
struct ThreadArgs
{
int srcClientIdx;
int dstClientIdx;
};
int portNumber=8090;
void * SocketThread(void *args)
{
printf("New thread created.\n");
struct ThreadArgs *threadArgs = (struct ThreadArgs*)args;
int sidx = threadArgs->srcClientIdx;
int didx = threadArgs->dstClientIdx;
int srcSocket = clients[sidx].socket;
int dstSocket = clients[didx].socket;
fd_set readfds;
struct timeval timeout;
while(1)
{
FD_ZERO(&readfds);
FD_SET(srcSocket, &readfds);
FD_SET(dstSocket, &readfds);
printf("Waiting for activities in thread.\n");
timeout.tv_sec = 60;
timeout.tv_usec = 0;
int activity = select(MAXCLIENTS+1, &readfds , NULL , NULL , &timeout);
if ((activity < 0) && (errno!=EINTR))
printf("Activity error.\n");
else if(activity == 0)
printf("Activity timeout.\n");
if (FD_ISSET(srcSocket, &readfds))
{
unsigned char buffer[FRAMESIZE];
int bytesCnt = read(srcSocket, buffer, sizeof(buffer));
if(bytesCnt == 0)
{
printf("Client%d disconnected.\n",sidx);
clients[sidx].state = 0;
clients[sidx].socket = -1;
pthread_exit(NULL);
}
else
printf("Client%d activity.\n",sidx);
}
if (FD_ISSET(dstSocket, &readfds))
{
unsigned char buffer[FRAMESIZE];
int bytesCnt = read(dstSocket, buffer, sizeof(buffer));
if(bytesCnt == 0)
{
printf("Client%d disconnected.\n",didx);
clients[didx].state = 0;
close(clients[didx].socket);
clients[didx].socket = -1;
pthread_exit(NULL);
}
else
printf("Client%d activity.\n",didx);
}
}
}
int ConfigureTCPIPconnection(int socket,struct sockaddr_in *serverAddr)
{
// Address family = Internet
serverAddr->sin_family = AF_INET;
//Set port number, using htons function to use proper byte order
serverAddr->sin_port = htons(portNumber);
//Incoming addresses
serverAddr->sin_addr.s_addr = INADDR_ANY;
//Set all bits of the padding field to 0
memset(serverAddr->sin_zero, '\0', sizeof serverAddr->sin_zero);
//Bind the address struct to the socket
if(bind(socket, (struct sockaddr *)serverAddr, sizeof(struct sockaddr)) < 0)
{
printf("Binding failed. %s\n",strerror(errno));
return 1;
}
printf("Bind sucessfull.\n");
return 0;
}
int CheckSocketActivity(fd_set *readfds)
{
int activity = select( MAXCLIENTS + 1 , readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
return 1;
return 0;
}
int main(int argc, char *argv[])
{
fd_set readfds;
int serverSocket,newSocket;
pthread_t td; //thread descriptor
struct sockaddr_in serverAddr, newAddr={0};
socklen_t addr_size;
clients[0].state = 0;
clients[0].socket = -1;
clients[1].state = 0;
clients[1].socket = -1;
if((serverSocket = socket(PF_INET, SOCK_STREAM, 0)) == 0)
{
printf("Server socket creation failed.\n");
exit(1);
}
if(ConfigureTCPIPconnection(serverSocket,&serverAddr))
{
printf("Binding failed.\n");
exit(2);
}
if(listen(serverSocket,MAXCLIENTS))
{
printf("Listen error.\n");
exit(3);
}
printf("Listening...\n");
while(1)
{
FD_ZERO(&readfds); //clear fd set
FD_SET(serverSocket, &readfds); //add server socket to fd set
if(clients[0].state == 1)
FD_SET(clients[0].socket, &readfds); //add active clients to fd set
if(clients[1].state == 1)
FD_SET(clients[1].socket, &readfds);
printf("Waiting for activities.\n");
if(!CheckSocketActivity(&readfds))
{
if(FD_ISSET(serverSocket, &readfds))
{
if((newSocket = accept(serverSocket, (struct sockaddr *)&newAddr, (socklen_t*)&addr_size))<0) //create new socket
printf("New socket error. %s\n",strerror(errno));
else
{
printf("New socket connected.\n");
if(clients[0].state == 0)
{
printf("Client0 added.\n");
clients[0].state = 1;
clients[0].socket = newSocket;
}
else if(clients[1].state == 0)
{
printf("Client1 added.\n");
clients[1].state = 1;
clients[1].socket = newSocket;
}
}
}
else
{
for(int i=0;i<2;i++)
{
int srcSock = clients[i].socket;
if (FD_ISSET(srcSock, &readfds))
{
unsigned char buffer[FRAMESIZE];
int bytesCnt = read(srcSock, buffer, sizeof(buffer));
if(bytesCnt == 0)
{
printf("Client%d disconnected.\n",i);
clients[i].state = 0;
close(clients[i].socket);
clients[i].socket = -1;
}
else
{
if(clients[0].state == 1 && clients[1].state == 1)
{
int srcIndex,dstIndex;
//some other stuff
clients[0].state = 2;
clients[1].state = 2;
if(i == 0)
{
srcIndex = 0;
dstIndex = 1;
}
else
{
srcIndex = 1;
dstIndex = 0;
}
printf("Creating new thread.\n");
struct ThreadArgs threadArgs = {srcIndex,dstIndex};
if(pthread_create(&td, NULL, SocketThread, &threadArgs) != 0)
printf("Failed to create thread.\n");
if (pthread_detach(td))
printf("Thread detach error.\n");
}
else
printf("Two clients required for creating thread.\n");
}
}
}
}
}
}
}

I assume you posted the code you are indeed dealing with because the code you posted shouldn't compile.
Correction 1 (May not be the source of the problem)
From the select() man page:
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
All FD_*() macros take fd_set* argument. In the main() you have passed fd_set instead of fd_set* at few places.
Correction 2 (May be the source of the problem)
In SocketThread() this piece of code might be the cause of the issue:
if (FD_ISSET(dstSocket, &readfds))
{
unsigned char buffer[FRAMESIZE];
bytesCnt = read(srcSock, buffer, sizeof(buffer));
if(bytesCnt == 0)
**//this is not detected**
else
//any other activities are detected
}
You may probably want read(dstSocket, buffer, sizeof(buffer));.

You say:
Select in main thread unblocks intself when one of the hosts from clients array disconnects. Then I try to read data, and when it is 0, client is disconnected. Why select in Thread doesn't work in the same way? It works perfect when clients exchange data, but there is no reaction, when one of clients disconnects.
Please, you don't say how the client disconnects. Does it just close the socket? does it do a shutdown? I don't see any close(2) on the socket, so why do you know who is closing the connection (or calling shutdown(2) to indicate that no more data is going to appear in the connection)?
normally, a connection blocks until you receive some data... receiving 0 data means no data has arrived or, after a select(2) call has selected a socket descriptor that show no more data, then you have the socket closed. But this has to be closed somewhere, and you show neither close(2) nor shutdown(2). You also don't describe what is what is detected on the socket. If you awake from the select(2) you get to the file descriptor and the result from read is not 0 what value does the read return? have you got acquainted that -1 is one of such possible values, and that it means you have a readin error? Do you check the value returned by select? (on timeout, my memory tells me that select(0) returns 0, so are you checking for timeout?)
Please, next time, provide a complete and verifiable example. The code you post cannot be made to run without a huge amount of contribution, so the problem can only be reproduced on your side. Check this page for some reading about how to post code in StackOverflow.

Related

How to read connections at the same time using select? sockets/c

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int port = 3008;
int listenfd;
extern void makelistener();
int main(int argc, char **argv)
{
makelistener();
int clientfd, nready;
socklen_t len;
struct sockaddr_in q;
int i;
// initialize allset and add listenfd to the
// set of file descriptors passed into select
fd_set allset;
fd_set rset;
int maxfd;
FD_ZERO(&allset);
FD_SET(listenfd, &allset); // set of file descriptors
maxfd = listenfd;
int ret;
while (1)
{
// make a copy of the set before we pass it into select
rset = allset;
/*select will wait until an exceptional event occurs when tv is NULL*/
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready == 0) {
continue;
}
if (nready == -1) {
perror("select");
continue;
}
//FD_ISSET returns 1 when a new connection is attempted
if(FD_ISSET(listenfd, &rset)){
//printf("a new client is connecting\n");
len = sizeof(q); //accept connection of listenfd stream socket
if ((clientfd = accept(listenfd, (struct sockaddr *)&q, &len)) < 0) {
perror("accept");
exit(1);
}
FD_SET(clientfd, &allset);
if (clientfd > maxfd) {
maxfd = clientfd;
}
static char msg[] = "What is your name?\r\n";
write(clientfd, msg, sizeof msg - 1);
printf("connection from %s\n", inet_ntoa(q.sin_addr));
char buf[256];
ret = read(clientfd, buf, sizeof(buf));
buf[ret] = '\0';
printf("%s", buf);
}
}
}
void makelistener()
{
struct sockaddr_in r;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
memset(&r, '\0', sizeof r);
r.sin_family = AF_INET;
r.sin_addr.s_addr = INADDR_ANY;
r.sin_port = htons(port);
if (bind(listenfd, (struct sockaddr *)&r, sizeof r)) {
perror("bind");
exit(1);
};
if (listen(listenfd, 5)) {
perror("listen");
exit(1);
}
}
above code is for the server and it does this
$ ./above.c
(does nothing but runs forever)
How to connect as a client:
$ nc 127.0.0.1 3000
What is your name?
(waiting for my input) so if I put bob, it would output it to the server
It works as intended. But I want it too work concurrently with multiple clients.
for example:
server
$ ./above.c
(does nothing but runs forever)
client1
$ nc 127.0.0.1 3000
What is your name?
client 2
$ nc 127.0.0.1 3000
What is your name? (Currently client2 wont show up until client1 is answered which is what I'm trying to fix)
How do I make it so the clients can run concurrently without waiting for the first client to finish? To explain the code a little bit, listener just binds and listens to a connection. Inside the while(1) is where select and calls are.
How do I make it so the clients can run concurrently without waiting for the first client to finish?
By paying attention to which sockets select() reports to you. You are asking select() to monitor multiple sockets for readability, but you are only checking if the listening socket is readable, you are not checking the client sockets. You need to keep track of the connected clients so you can enumerate them when needed.
Try something like this:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int port = 3008;
#define MAX_CLIENTS (FD_SETSIZE - 1)
int listenfd = -1;
extern void makelistener();
int main(int argc, char **argv)
{
int clientfd, nready;
socklen_t len;
struct sockaddr_in q;
int i, j, ret;
fd_set allset;
fd_set rset;
int clients[MAX_CLIENTS];
int num_clients = 0;
int maxfd;
char buf[256];
makelistener();
// initialize allset and add listenfd to the
// set of file descriptors passed into select
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
maxfd = listenfd;
while (1)
{
// make a copy of the set before we pass it into select
FD_COPY(&allset, &rset);
// select will wait until an exceptional event occurs when tv is NULL
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready < 0) {
perror("select");
continue;
}
if (nready == 0) { // should never happen since no timeout was requested
continue;
}
//FD_ISSET returns 1 when a socket is readable
if (FD_ISSET(listenfd, &rset)) {
//printf("a new client is connecting\n");
len = sizeof(q); //accept connection of listenfd stream socket
if ((clientfd = accept(listenfd, (struct sockaddr *)&q, &len)) < 0) {
perror("accept");
exit(1);
}
printf("Client %d connected from %s\n", clientfd, inet_ntoa(q.sin_addr));
if (num_clients == MAX_CLIENTS) {
static char msg[] = "Max number of clients are already connected\r\n";
write(clientfd, msg, sizeof(msg)-1);
close(clientfd);
}
else {
static char msg[] = "What is your name?\r\n";
if (write(clientfd, msg, sizeof(msg)-1) < 0) {
close(clientfd);
}
else {
clients[num_clients++] = clientfd;
FD_SET(clientfd, &allset);
if (clientfd > maxfd) {
maxfd = clientfd;
}
}
}
}
for (i = 0; i < num_clients; ++i) {
clientfd = clients[i];
if (!FD_ISSET(clientfd, &rset)) {
continue;
}
ret = read(clientfd, buf, sizeof(buf));
if (ret <= 0) {
//printf("a client has disconnected\n");
close(clientfd);
FD_CLR(clientfd, &allset);
for (j = i + 1; j < num_clients; ++j) {
clients[j-1] = clients[j];
}
--num_clients;
if (clientfd == maxfd) {
maxfd = listenfd;
for (j = 0; j < num_clients; ++j) {
if (clients[j] > maxfd) {
maxfd = clients[j];
}
}
}
--i;
continue;
}
printf("Client %d: %.*s", clientfd, ret, buf);
}
}
return 0;
}
Note that poll() or epoll() would generally be a better choice to use than select().
How do I make it so the clients can run concurrently without waiting for the first client to finish?
every time that the call to accept() returns, start a thread pthread_create() to handle the actual communication with the client.
Note: creating/destroying a thread is very time consuming, so suggest learning about thread pools and how to use them.
When using threads, there is no call to select() (nor poll()) Rather the main function gets blocked on the call to accept() and when that function returns, pass the associated socket to a thread to handle
There are lots of example code for how a server should communicate with multiple clients on stackoverflow.com

No response from recv when using nonblocking socket

I am trying to create a portscanner in c. If the port is open, I want to get a response from the server. When I use regular blocking sockets, this works fine. For example, I know that for a certain address on my network, if I check port 80, it will return the html page to me when I call recv. I have tested this, and it works correctly every time.
However, I want to use nonblocking sockets, because sometimes certain servers will not respond and will cause the program to hang. I was able to get the nonblocking sockets to (kindof) work (the code is currently commented out below). I could see which ports were open, which were closed, and which timed out, but I was not able to get a response from the server (even though I know it should send one). What am I doing wrong?
tl;dr: When using nonblocking sockets (vs blocking), recv doesn't return any data.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#define MAX_LEN 100000
int main(int argc, char **argv)
{
int sock, test_sock;
struct sockaddr_in server_addr;
struct hostent *hp;
char buf[MAX_LEN];
int num_bytes;
int err_code;
int START_PORT = 1;
int END_PORT = 100;
fd_set fdset;
struct timeval tv;
int opts;
// resolve server name for its IP address, etc.
hp = gethostbyname(argv[1]);
if (NULL == hp) {
perror("gethostbyname");
exit(2);
}
//printf("Here1\n");
// build remote server addr/port
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
//server_addr.sin_port = htons(atoi(argv[2]));
test_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
for(int i=START_PORT; i<=END_PORT; i++) {
printf("Here2\n");
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //created the tcp socket
//opts = fcntl(sock, F_SETFL, O_NONBLOCK);
printf("Here3\n");
if (sock < 0)
{
perror("Socket()\n");
exit(1);
}
server_addr.sin_port = htons(i);
// connect to server
printf("Here4\n");
err_code = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
printf("Here5\n");
/* ... */
if (err_code < 0) {
printf("Port %d: connection refused\n", i);
//exit(3);
} else {
printf("Port %d:\n", i);
memset(buf, 0, MAX_LEN);
// Create message to send
char message[256];
strcpy(message, "GET / HTTP/1.0\r\nHost: ");
strcat(message, argv[1]);
strcat(message, "\r\n\r\n");
unsigned total_bytes_sent = 0;
num_bytes = send(sock, message, strlen(message), 0);
if (num_bytes < 0) {
perror("send");
exit(4);
}
unsigned total_bytes_received = 0;
while(1) {
num_bytes = recv(sock, buf+total_bytes_received, MAX_LEN, 0);
if(num_bytes <= 0){
break;
}
total_bytes_received += num_bytes;
}
// display received ack message
//printf("Port %d:\n", i);
fflush(stdout);
write(1, buf, total_bytes_received);
printf("\n");
printf("Done...\n");
}
close(sock);
}
// close sock to release resource
close(sock);
return 0;
}
SOLUTION
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#define MAX_LEN 100000
int main(int argc, char **argv)
{
int sock, sock_test;
struct sockaddr_in server_addr;
struct hostent *hp;
char buf[MAX_LEN];
int num_bytes;
int err_code;
int START_PORT = 1;
int END_PORT = 100;
int valid = 1;
fd_set fdset;
struct timeval tv;
// resolve server name for its IP address, etc.
hp = gethostbyname(argv[1]);
if (NULL == hp) {
perror("gethostbyname");
exit(2);
}
// build remote server addr/port
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
for(int i=START_PORT; i<=END_PORT; i++) {
sock_test = socket(AF_INET, SOCK_STREAM, 0);
if (sock_test < 0)
{
perror("Socket()\n");
exit(1);
}
fcntl(sock_test, F_SETFL, O_NONBLOCK);
server_addr.sin_port = htons(i);
connect(sock_test, (struct sockaddr *)&server_addr, sizeof(server_addr));
FD_ZERO(&fdset);
FD_SET(sock_test, &fdset);
tv.tv_sec = 3;
tv.tv_usec = 0;
if (select(sock_test + 1, NULL, &fdset, NULL, &tv) == 1)
{
int so_error;
socklen_t len = sizeof so_error;
getsockopt(sock_test, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error == 0) {
printf("%s:%d is open\n", argv[1], i);
memset(buf, 0, MAX_LEN);
// Create message to send
char message[256];
strcpy(message, "GET / HTTP/1.0\r\nHost: ");
strcat(message, argv[1]);
strcat(message, "\r\n\r\n");
printf("Here6\n");
unsigned total_bytes_sent = 0;
num_bytes = send(sock_test, message, strlen(message), 0);
printf("Here7\n");
int retry = 3;
unsigned total_bytes_received = 0;
while(retry) {
num_bytes = recv(sock_test, buf+total_bytes_received, MAX_LEN, 0);
if (0 == num_bytes)
{
/* socket has been closed by peer */
break;
}
else if(-1 == num_bytes)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
/* no data to be read on socket */
retry--;
/* wait one second */
sleep(1);
}
else
{
/* other error */
perror("recv");
break;
}
}
else
{
total_bytes_received += num_bytes;
}
}
// display received ack message
//printf("Port %d:\n", i);
fflush(stdout);
write(1, buf, total_bytes_received);
printf("\n");
printf("Done...\n");
}
else
{
//printf("%s:%d is closed\n", argv[1], i);
}
} else {
printf("timed out\n");
valid = 0; //set the boolean flag to false
}
close(sock_test);
}
// close sock to release resource
close(sock_test);
return 0;
}
As pointed in comments, in non-blocking mode, you have to handle cases when
server is not ready to send data.
For man recv(3)
Return Value
Upon successful completion, recv() shall return the length of the message in bytes. If no messages are available to be received and the peer has performed an orderly shutdown, recv() shall return 0. Otherwise, -1 shall be returned and errno set to indicate the error.
Errors
The recv() function shall fail if:
EAGAIN or EWOULDBLOCK
The socket's file descriptor is marked O_NONBLOCK and no data is waiting to be received; or MSG_OOB is set and no out-of-band data is available and either the socket's file descriptor is marked O_NONBLOCK or the socket does not support blocking to await out-of-band data.
Since your client may try to read before the server send something, you must
adapt your code to wait:
/* maximum number of retry, one second per retry */
int retry = 10;
unsigned total_bytes_received = 0;
while(retry) {
num_bytes = recv(sock, buf+total_bytes_received, MAX_LEN, 0);
if (0 == num_bytes)
{
/* socket has been closed by peer */
break;
}
else if(-1 == num_bytes)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
/* no data to be read on socket */
retry--;
/* wait one second */
sleep(1);
}
else
{
/* other error */
perror("recv");
break;
}
}
else
{
total_bytes_received += num_bytes;
}
}

Multiclient Server Implementation in C

I am trying to implement multi client server using C. I have write code for server and client is a software that will continuously send some packet to server. Server will read the packet and process it. I am trying for 5 connection at a time to server. But there is some problem with server code that I have written due to which I can not connect 5 client to server. Exact Problem is that when client is trying to connect with server it gets connection for but when I close client software and try to start again it is not getting connection. Following is my code for server side. can anybody help me regarding this problem.
#include <ctype.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/file.h>
int sock; /* The socket file descriptor for our "listening"socket */
int connectlist[15]; /* Array of connected sockets so we know who we are talking to */
fd_set socks; /* Socket file descriptors we want to wake up for, using select() */
int highsock = 1; /* Highest #'d file descriptor, needed for select() */
struct sockaddr_in client_address[5];
unsigned int clientLength = sizeof(client_address) ;
#define PORTNO (int)49153
int port; /* The port number after conversion from ascport */
struct sockaddr_in server_address; /* bind info structure */
int reuse_addr = 1;
struct timeval timeout; /* Timeout for select */
int readsocks; /* Number of sockets ready for reading */
int err = 0 ;
#define BACKLOG (int)10
void deal_with_data(int listnum /* Current item in connectlist for for loops */)
{
//Here I am trying to read packet from client s/w and process it
}
void setnonblocking(int sock)
{
int opts;
opts = fcntl(sock,F_GETFL);
if (opts < 0)
{
printf("fcntl(F_GETFL)_error");
exit(0);
}
opts = (opts | O_NONBLOCK);
if (fcntl(sock,F_SETFL,opts) < 0)
{
printf("fcntl(F_SETFL)_error");
exit(0);
}
return;
}
void build_select_list()
{
int listnum; /* Current item in connectlist for for loops */
FD_ZERO(&socks);
FD_SET(sock,&socks);
for (listnum = 0; listnum < 5; listnum++)
{
if (connectlist[listnum] != 0)
{
FD_SET(connectlist[listnum],&socks);
if (connectlist[listnum] > highsock)
highsock = connectlist[listnum];
}
}
}
void handle_new_connection() {
int listnum; /* Current item in connectlist for for loops */
int connection; /* Socket file descriptor for incoming connections */
connection = accept(sock, (struct sockaddr *)&client_address[highsock], &clientLength);
if (connection < 0)
{
printf("accept_error");
exit(0);
}
setnonblocking(connection);
for (listnum = 0; (listnum < 5) && (connection != -1); listnum ++)
if (connectlist[listnum] == 0)
{
printf("\nConnection accepted: FD=%d; Slot=%d\n",
connection,listnum);
printf("Connection accepted from %s\n",inet_ntoa(client_address[highsock].sin_addr));
connectlist[listnum] = connection;
connection = -1;
}
if (connection != -1)
{
printf("\nNo room left for new client.\n");
write(connection,"Sorry, this server is too busy.Try again later!\r\n",80);
close(connection);
}
printf("return from handle_new_connection\n");
}
void read_socks(void)
{
int listnum; /* Current item in connectlist for for loops */
if (FD_ISSET(sock,&socks))
handle_new_connection();
for (listnum = 0; listnum < 5; listnum++)
{
if (FD_ISSET(connectlist[listnum],&socks))
{
//printf("read_socks2\n");
deal_with_data(listnum);
}
}
}
int main (/*int argc, char *argv[]*/)
{
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0)
{
printf("socket_error");
exit(EXIT_FAILURE);
}
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr));
setnonblocking(sock);
memset((char *) &server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &server_address,sizeof(server_address)) < 0 )
{
printf("bind_error");
close(sock);
exit(EXIT_FAILURE);
}
if((err = listen(sock,10)) == -1)
{
printf("listen_error");
}
highsock = sock;
memset((char *) &connectlist, 0, sizeof(connectlist));
while (1)
{ /* Main server loop - forever */
build_select_list();
timeout.tv_sec = 2;
timeout.tv_usec = 0;
readsocks = select(highsock+2, &socks, (fd_set *) 0,(fd_set *) 0, &timeout);
if (readsocks < 0)
{
printf("select_error");
exit(EXIT_FAILURE);
}
if (readsocks == 0)
{
printf(".");
fflush(stdout);
}
else
{
read_socks();
}
} /* while(1) */
} /* main */
Your problem is that your main loop doesn't exit when the socket has been closed by the client. This means that it cannot accept new connections. I would use fork() to do the processing of the data from the socket, and the main() function to accept connections and fork() the process. Also, you need to have some code which will kill the fork()ed (i.e. to check if the client has disconnected in the fork()ed process) process (since it won't close by itself and it takes up memory).
EDIT:
Ok, I can't find a call to recv() in your program. According the the recv(3) man page it will return 0 if the client disconnect "gracefully" and return -1 and set errno to ECONNRESET if the client forcefully disconnected. In order to use fork, I would (in the main() function) wrap your while loop in this:
int childpid = fork();
if(childpid == -1) {
printf("Could not fork process");
exit(EXIT_FAILURE);
}
else if(childpid == 0) { /* in child process*/
while(/* check if the socket has been closed */) {
/* While loop stuff */
}
/* free up memory */
exit(EXIT_SUCCESS);
}
And your main function should be in a loop, waiting for new connections.
N.B. I have not tested any of this code, so it might not work. But if you read the man pages for fork(3) and recv(3) it should work.
Aren't you better off using something off the shelf like Apache and customize it as necessary?

Delay on recieving message on (select) chat-client

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.

bluetooth socket not receiving packet

I am working on a bluetooth socket for past 10 days. I have to switch between client and server mode. I have written a piece of code. I was able to send the packet fine but when i was working for listening mode I faced two problems.
1.The accept was in block mode so it was not able to go back to send mode.
2. I made the socket non block using FNCTL()
But now issue is coming that is is switching between two modes perfectly but it is not receiving any packet. My code is as follow:-
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/l2cap.h>
#define MAXPROFILES 2
int SetTimer(struct timeval *tv, time_t sec)
{
gettimeofday(tv,NULL);
tv->tv_sec+=sec;
return 1;
}
void start_scan()
{
struct sockaddr_l2 addr1 = { 0 };
int s=0,h, status,f,contacted;
int search=1;
char *message = "hello!";
char dest[18] = "01:23:45:67:89:AB";
struct neighbor
{
char peer[19];
} p[h];
unsigned char buf[1024];
inquiry_info *devices = NULL;
int max_rsp, num_rsp;
int dev_id, sock, len, flags,cmp;
int x=0,i;
char addr[19] = { 0 };
char name[248] = { 0 };
dev_id = hci_get_route(NULL);
sock = hci_open_dev( dev_id );
if (dev_id < 0 || sock < 0)
{
perror("opening socket");
exit(1);
}
len = 3;
max_rsp = 255;
flags = IREQ_CACHE_FLUSH;
devices = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
struct timeval tv;
SetTimer(&tv,15);
while(search == 1)
{ //fprintf(stderr,"\t%d \n", time);
num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &devices, flags);
fprintf(stderr,"%s (%d) %d\n", "done scanning, found ", j, num_rsp);
if( num_rsp < 0 ) perror("hci_inquiry");
for (i = 0; i < num_rsp; i++)
{
ba2str(&(devices+i)->bdaddr, addr);
fprintf(stderr,"\t%s \n", addr);
cmp= strncmp(addr,"10:2E:AF:EB:33:BD",8);
if(cmp==0)
{
fprintf(stderr,"\t%s \t%d\n", addr,cmp);
for(f=0;f<=h;f++)
{
if(p[f].peer[18]==addr[19])
contacted=1;
}
if(contacted==1)
{
contacted=0;
continue;
}
s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
// set the connection parameters (who to connect to)
addr1.l2_family = AF_BLUETOOTH;
addr1.l2_psm = htobs(0x1001);
strncpy(dest, addr, 18);
str2ba( dest, &addr1.l2_bdaddr );
// connect to server
status = connect(s, (struct sockaddr *)&addr1, sizeof(addr1));
// send a message
if( status == 0 )
{
status = write(s, "hello", 10);
h++;
p[h].peer[18]=addr[19];
}
if( status < 0 )
{
perror("uh oh");
}
}
} // for
x++;
if(!(x%2))
flags = IREQ_CACHE_FLUSH;
else
flags = 0x00;
if (CheckTimer(&tv,5)==1)
{ //close(sock);
fprintf(stderr,"listen....\n");
start_listen(s);
}
}
}
int start_listen(int s)
{ struct sockaddr_l2 addr1 = { 0 },rem_addr = { 0 };;
fd_set fds;
int client, bytes_read,sock_flags;
char buf1[1024] = {0};
socklen_t opt = sizeof(rem_addr);
struct timeval tv;
addr1.l2_family = AF_BLUETOOTH;
addr1.l2_bdaddr = *BDADDR_ANY;
addr1.l2_psm = htobs(0x1001);
sock_flags=fcntl(s,F_GETFL,0);
fcntl(s,F_SETFL,sock_flags | O_NONBLOCK);
bind(s, (struct sockaddr *)&addr1, sizeof(addr1));
SetTimer(&tv,15);
// put socket into listening mode
while(!0)
{
listen(s, 1);
//fprintf(stderr,"I am listening....\n");
// accept one connection
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
//fprintf(stderr,"I failed....\n");
FD_ZERO(&fds);
FD_SET(s,&fds);
ba2str( &rem_addr.l2_bdaddr, buf1 );
memset(buf1, 0, sizeof(buf1));
// read data from the client
bytes_read = read(client, buf1, sizeof(buf1));
if( bytes_read > 0 ){
printf("received [%s]\n", buf1);
fprintf(stderr, "accepted connection from %s\n", buf1);
}
close(client);
if (CheckTimer(&tv,5)==1)
{fprintf(stderr,"done listening...");
SetTimer(&tv,15);
return 1;
}
}//while of the listening mode
}
int CheckTimer(struct timeval *tv, time_t sec)
{
struct timeval ctv;
gettimeofday(&ctv,NULL);
if((ctv.tv_sec > tv->tv_sec))
{
gettimeofday(tv,NULL);
tv->tv_sec+=sec;
return 1;
}
else return 0;
}
int main(int argc, char **argv)
{start_scan();
}
I was able to solve the issue by entering the following command again in listen mode before binding.
s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
But now the issue is my close(client) is not working. I am not able to close the client and listen to new client. Do anyone know why?
There is no need at all to open the server socket! (Unless your remote device is doing something very odd!!) A socket can be used for send and receive -- regardless of whether it is a client socket or a server socket.
Remove all the code to do the listen+accept etc, and write and read to the original (client) socket.(The one done with: "connect(s,...")
If your remote device really needs the two different connections. The use a new variable to hold the socket handle and don't have the server socket handle overwrite the original client handle.

Resources