I have a little doubt with an excercise that i have found to train my ability with sockets.
The exercise says:
Write pseudocode of a tcp server based on fork()
Constraints:
- Max 20000 simultaneusly active connections; after this limit new connection are dropped
- At most 1000 request per client(ip) per hour
I've sketched a solution and i want to know if's it's a good way to go:
struct client{
int ip;
timestamp to;
int n_req;
client* next;
}
void serve(int c_fd, int ip, client* list){
client* c = find_in_list(list, ip);
timestamp now = gettimeofday();
if(now.tv_sec - c->to.tv_sec > (60*60)){
// ig one hour is passed is possible to reset counter
c->n_req = 0;
c->to = now;
}
if(c->n_req > 1000){
/*do_nothing */
} else {
n_req++;
/*
do stuff
*/
}
exit();
}
int main(){
client* list = NULL;
a_fd = socket(AF_INET);
bind(a_fd);
listen(a_fd);
while(1){
/*inizilize poll*/
n_ready = poll();
if(n_ready > 0){
for(/*each ready file descriptor*/){
c_fd = accept(a_fd, this_sockaddr);
if(/* if the ip in this_sockaddr is new*/){
client* new = /*create neew client */;
add_list(list, new);
}
if(served <= 20000){
served++;
pid = fork();
if(pid == 0 ){ //CHILD
serve(c_fd, ip, list);
close(c_fd)
} else { //FATHER
close(c_fd);
do{
pid = blocking_wait();
served--;
} while(pid != 0)
}
} else {
close(c_fd);
}
}
}
}
}
Thanks for any advice.
If you want to see a simple, yet fully effective example of a server using fork, I would recommend you review this simple little project:
ftp://ftp.cs.umass.edu/pub/net/pub/kurose/ftpserver.c
if (listen(sockid,5) < 0)
{ printf("server: listen error :%d\n",errno);exit(0);}
while(1==1) {
/* ACCEPT A CONNECTION AND THEN CREATE A CHILD TO DO THE WORK */
/* LOOP BACK AND WAIT FOR ANOTHER CONNECTION */
printf("server: starting accept\n");
if ((newsd = accept(sockid ,(struct sockaddr *) &client_addr,
&clilen)) < 0)
{printf("server: accept error :%d\n", errno); exit(0); }
printf("server: return from accept, socket for this ftp: %d\n",
newsd);
if ( (pid=fork()) == 0) {
/* CHILD PROC STARTS HERE. IT WILL DO ACTUAL FILE TRANSFER */
close(sockid); /* child shouldn't do an accept */
doftp(newsd);
close (newsd);
exit(0); /* child all done with work */
}
/* PARENT CONTINUES BELOW HERE */
close(newsd); /* parent all done with client, only child */
} /* will communicate with that client from now on */
Child fork looks like this:
/* CHILD PROCEDURE, WHICH ACTUALLY DOES THE FILE TRANSFER */
doftp(int newsd)
{
int i,fsize,fd,msg_ok,fail,fail1,req,c,ack;
int no_read ,num_blks , num_blks1,num_last_blk,num_last_blk1,tmp;
char fname[MAXLINE];
char out_buf[MAXSIZE];
FILE *fp;
no_read = 0;
num_blks = 0;
num_last_blk = 0;
/* START SERVICING THE CLIENT */
/* get command code from client.*/
/* only one supported command: 100 - get a file */
req = 0;
if((readn(newsd,(char *)&req,sizeof(req))) < 0)
{printf("server: read error %d\n",errno);exit(0);}
req = ntohs(req);
...
Related
I have a small problem, in practice I have to let two clients communicate (which perform different functions), with my concurrent server,
I discovered that I can solve this using the select, but if I try to implement it in the code it gives me a segmentation error, could someone help me kindly?
I state that before with a single client was a fable, now unfortunately implementing the select, I spoiled a bit 'all,
I should fix this thing, you can make a concurrent server with select ()?
can you tell me where I'm wrong with this code?
int main (int argc , char *argv[])
{
int list_fd,conn_fd;
int i,j;
struct sockaddr_in serv_add,client;
char buffer [1024];
socklen_t len;
time_t timeval;
char fd_open[FD_SETSIZE];
pid_t pid;
int logging = 1;
char swi;
fd_set fset;
int max_fd = 0;
int waiting = 0;
int compat = 0;
sqlite3 *db;
sqlite3_open("Prova.db", &db);
start2();
start3();
printf("ServerREP Avviato \n");
if ( ( list_fd = socket(AF_INET, SOCK_STREAM, 0) ) < 0 ) {
perror("socket");
exit(1);
}
if (setsockopt(list_fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0)
perror("setsockopt(SO_REUSEADDR) failed");
memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
serv_add.sin_family = AF_INET;
serv_add.sin_port = htons(SERVERS_PORT2);
serv_add.sin_addr.s_addr = inet_addr(SERVERS_IP2);
if ( bind(list_fd, (struct sockaddr *) &serv_add, sizeof(serv_add)) < 0 ) {
perror("bind");
exit(1);
}
if ( listen(list_fd, 1024) < 0 ) {
perror("listen");
exit(1);
}
/* initialize all needed variables */
memset(fd_open, 0, FD_SETSIZE); /* clear array of open files */
max_fd = list_fd; /* maximum now is listening socket */
fd_open[max_fd] = 1;
//max_fd = max(conn_fd, sockMED);
while (1) {
FD_ZERO(&fset);
FD_SET(conn_fd, &fset);
FD_SET(sockMED, &fset);
len = sizeof(client);
if(select(max_fd + 1, &fset, NULL, NULL, NULL) < 0){exit(1);}
if(FD_ISSET(conn_fd, &fset))
{
if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len)) <0 )
perror("accept error");
exit(-1);
}
/* fork to handle connection */
if ( (pid = fork()) < 0 ){
perror("fork error");
exit(-1);
}
if (pid == 0) { /* child */
close(list_fd);
close(sockMED);
Menu_2(db,conn_fd);
close(conn_fd);
exit(0);
} else { /* parent */
close(conn_fd);
}
if(FD_ISSET(sockMED, &fset))
MenuMED(db,sockMED);
FD_CLR(conn_fd, &fset);
FD_CLR(sockMED, &fset);
}
sqlite3_close(db);
exit(0);
}
I cannot understand how you are trying to use select here, and why you want to use both fork to let a child handle the accepted connection socket, and select.
Common designs are:
multi processing server:
The parent process setups the listening socket and loops on waiting actual connections with accept. Then it forks a child to process the newly accepted connection and simple waits for next one.
multi threaded server:
A variant of previous one. The master thread starts a new thread to process the newly accepted connection instead of forking a new process.
asynchronous server:
The server setups a fd_set to know which sockets require processing. Initially, only the listening socket is set. Then the main loop is (in pseudo code:
loop on select
if the listening socket is present in read ready sockets, accept the pending connection and add is to the `fd_set`, then return to loop
if another socket is present in read ready socket
read from it
if a zero read (closed by peer), close the socket and remove it from the `fd_set`
else process the request and return to loop
The hard part here is that is processing takes a long time, the whole process is blocked, and it processing involves sending a lot of data, you will have to use select for the sending part too...
I want to make a simple chat application for unix.
I have created one server which supports multiple clients. When ever a new client connects to the server a new process is created using fork command. Now the problem is all the child processes share the same stdin on the server, cause of this in order to send a message to 2nd clien 1st child prosess has to terminte. In order to resolve this I would like to run each child process in a new terminal.
This can be achieved by writing the code for the child process code in a new file and executing it like xterm -e sh -c .(i have not tried this though).
What i really want is not to have two file just to fireup a new terminal and run rest of the code in it.
int say(int socket)
{
char *s;
fscanf(stdin,"%79s",s);
int result=send(socket,s,strlen(s),0);
return result;
}
int main()
{
int listener_d;
struct sockaddr_in name;
listener_d=socket(PF_INET,SOCK_STREAM,0);
name.sin_family=PF_INET;
name.sin_port=(in_port_t)htons(30000);
name.sin_addr.s_addr=htonl(INADDR_ANY);
int c = bind(listener_d,(struct sockaddr *)&name,sizeof(name)); //Bind
if(c== -1)
{
printf("\nCan't bind to socket\n");
}
if(listen(listener_d,10) == -1) // Listen
{
printf("\nCan't listen\n");
}
puts("\nWait for connection\n");
while(1)
{
struct sockaddr_storage client_addr;
unsigned int address_size = sizeof(client_addr);
int connect_d = accept(listener_d,
(struct sockaddr*)&client_addr,&address_size); //Accept
if(connect_d== -1)
{
printf("\nCan't open secondary socket\n");
}
if(!fork())
{
close(listener_d);
char *msg = "welcome Sweetone\n";
if(send(connect_d,msg,strlen(msg),0))
{
printf("send");
}
int k=0;
while(k<5)
{
say(connect_d);
++k;
}
close(connect_d);
exit(0);
}
close(connect_d);
}
close(listener_d);
return 0;
}
I think the message sending between your client and servers is a bit unusual. It is more common, in this simple "just test how it works" scenario to have the clients sending messages to the server. As an example I could mention a simple echo service, which mirrors everything a client sends, back to the client. Is this design forced by some requirements?
Critique aside, I have two separate changes that could make your current design work. They both involve changing the reading of input in the subservers.
Alternative 1:
Instead of reading from stdin, create a named pipe ( see man 3 mkfifo), fex /tmp/childpipe"pid_of_subserver_here". You could create the pipe in say() and open it for reading. Then use echo (man echo) to write to the pipe echo "My message" > /tmp/childpipe"NNNN". Before exiting the child, remember to remove the pipe with unlink()
Alternative 2:
Create an unnamed pipe between server and each subserver. This makes the code much more messy, but avoids creating named pipes and using echo. Example code is included below. It has insufficient error handling (like most example code) and does not handle disconnecting client properly.
Example usage: 1) start server ./a.out 2) (connect client in external window (e.g. nc localhost 30000) 3) write to client 1 by typing "1Hello client one" 4) (connect second client in third window etc) 4) Write to second client by typing "2Hello second client"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
enum max_childeren{
MAX_CHILDEREN = 50
};
int say(int socket)
{
char buf[513] = {0};
fgets(buf, sizeof(buf), stdin);
int result=send(socket, buf, strlen(buf),0);
return result;
}
int main()
{
int listener_d;
struct sockaddr_in name;
listener_d=socket(PF_INET,SOCK_STREAM,0);
name.sin_family=PF_INET;
name.sin_port=(in_port_t)htons(30000);
name.sin_addr.s_addr=htonl(INADDR_ANY);
int on = 1;
if (setsockopt(listener_d, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0){
perror("setsockopt()");
}
int c = bind(listener_d,(struct sockaddr *)&name,sizeof(name)); //Bind
if(c== -1)
{
printf("\nCan't bind to socket\n");
}
if(listen(listener_d,10) == -1) // Listen
{
printf("\nCan't listen\n");
}
// Edited here
int number_of_childeren = 0;
int pipes[2] = {0};
int child_pipe_write_ends[MAX_CHILDEREN] = {0};
fd_set select_fds;
FD_ZERO(&select_fds);
puts("\nWait for connection\n");
while(1)
{
struct sockaddr_storage client_addr;
unsigned int address_size = sizeof(client_addr);
// Edited here, to multiplex IO
FD_SET(listener_d, &select_fds);
FD_SET(STDIN_FILENO, &select_fds);
int maxfd = listener_d + 1;
int create_new_child = 0;
int connect_d = -1; // moved here
select(maxfd, &select_fds, NULL, NULL, NULL);
if (FD_ISSET(listener_d, &select_fds)){
connect_d = accept(listener_d,
(struct sockaddr*)&client_addr,&address_size); //Accept
if(connect_d== -1)
{
printf("\nCan't open secondary socket\n");
exit(EXIT_FAILURE);
}
create_new_child = 1;
}
char buf[512] ={0};
char *endptr = NULL;
if (FD_ISSET(STDIN_FILENO, &select_fds)){
fgets(buf, sizeof(buf), stdin);
long int child_num = strtol(buf, &endptr, 10);
if (child_num > 0 && child_num <= number_of_childeren) {
write(child_pipe_write_ends[child_num - 1], endptr, strnlen(buf, sizeof(buf)) - (endptr - buf));
}
else {
printf("Skipping invalid input: %s\n", buf);
}
}
if (create_new_child != 1)
continue;
number_of_childeren++; // Edited here
int error = pipe(pipes);
if (error != 0){
//handle errors
perror("pipe():");
exit(EXIT_FAILURE);
}
child_pipe_write_ends[number_of_childeren - 1] = pipes[1];
if(!fork())
{
error = dup2(pipes[0], STDIN_FILENO);
if (error < 0){ // could also test != STDIN_FILENO but thats confusing
//handle errors
perror("dup2");
exit(EXIT_FAILURE);
}
close(pipes[0]);
close(listener_d);
char *msg = "welcome Sweetone\n";
if(send(connect_d,msg,strlen(msg),0))
{
printf("send\n");
}
int k=0;
while(k<5)
{
say(connect_d);
++k;
}
close(connect_d);
exit(0);
}
close(connect_d);
close(pipes[0]);
}
close(listener_d);
return 0;
}
The code needs refactoring into functions. It is too long. I tried to do the least possible amount of changes, so I left the restructuring as an exercise.
fscanf(stdin,"%79s",s);
Why? Is it tcp-chat? You have some socket for each client and if yoy want to "say" something then you must to use client. It's true logick.
The server usually sends a service messages only. It's true logick too.
But if you want new terminal then you can try to use a exec's family from unistd.h .
Objective: N nodes (running on different machines) should communicate with each other by establishing TCP connections with each other. Sending and receiving messages are done by 2 threads created by the process. Initially the main process connects all nodes with each other, creates the 2 threads and gives it a list of file descriptors which can be used by threads to send and receive data. The below structure is filled by the main process and passed to the threads.
typedef struct
{
char hostName[MAXIMUM_CHARACTERS_IN_HOSTNAME]; /* Host name of the node */
char portNumber[MAXIMUM_PORT_LENGTH]; /* Port number of the node */
char nodeId[MAXIMUM_NODE_ID_LENGTH]; /* Node ID of the node */
int socketFd; /* Socket file descriptor */
int socketReady; /* Flag to indicate if socket information is filled */
}SNodeInformation;
PS: socketFd is the socket descriptor received by either accept() or by socket() depending on how the connection was established (Either listening to connections from a node or connecting to a node).
An array of SNodeInformation of size MAX_NUM_OF_NODES is used.
The send thread goes through the nodeInformation and sends a message "Hello" to all nodes as except itself show below.
void *sendMessageThread(void *pNodeInformation) {
int i;
int ownNodeId;
int bytesSent = 0;
char ownHostName[MAXIMUM_CHARACTERS_IN_HOSTNAME];
SNodeInformation *nodeInformation = (SNodeInformation *) pNodeInformation;
SNodeInformation *iterNodeInformation;
printf("SendMessageThread: Send thread created\n");
if(gethostname(ownHostName, MAXIMUM_CHARACTERS_IN_HOSTNAME) != 0) {
perror("Error: sendMessageThread, gethostname failed\n");
exit(1);
}
for(i=0, iterNodeInformation=nodeInformation ; i<MAXIMUM_NUMBER_OF_NODES ; i++, iterNodeInformation++) {
if(strcmp((const char*) iterNodeInformation->hostName, (const char*) ownHostName) != 0) {
/* Send message to all nodes except yourself */
bytesSent = send(iterNodeInformation->socketFd, "Hello", 6, 0);
if(bytesSent == -1) {
printf("Error: sendMessageThread, sending failed, code: %s FD %d\n", strerror(errno), iterNodeInformation->socketFd);
}
}
}
pthread_exit(NULL);
}
The receive thread goes through the nodeInformation, sets up a file descriptor set and uses select to wait for incoming data as show below.
void *receiveMessageThread(void *pNodeInformation)
{
int i;
int fileDescriptorMax = -1;
int doneReceiving = 0;
int numberOfBytesReceived = 0;
int receiveCount = 0;
fd_set readFileDescriptorList;
char inMessage[6];
SNodeInformation *nodeInformation = (SNodeInformation *) pNodeInformation;
SNodeInformation *iterNodeInformation;
printf("ReceiveMessageThread: Receive thread created\n");
/* Initialize the read file descriptor */
FD_ZERO(&readFileDescriptorList);
for(i=0, iterNodeInformation=nodeInformation ; i<MAXIMUM_NUMBER_OF_NODES ; i++, iterNodeInformation++) {
FD_SET(iterNodeInformation->socketFd, &readFileDescriptorList);
if(iterNodeInformation->socketFd > fileDescriptorMax) {
fileDescriptorMax = iterNodeInformation->socketFd;
}
}
printf("ReceiveMessageThread: fileDescriptorMax:%d\n", fileDescriptorMax);
while(!doneReceiving) {
if (select(fileDescriptorMax+1, &readFileDescriptorList, NULL, NULL, NULL) == -1) {
perror("Error receiveMessageThread, select failed \n");
return -1;
}
for(i=0 ; i<fileDescriptorMax ; i++) {
if (FD_ISSET(i, &readFileDescriptorList)) {
/* Check if any FD was set */
printf("ReceiveThread: FD set %d\n", i);
/* Receive data from one of the nodes */
if ((numberOfBytesReceived = recv(i, &inMessage, 6, 0)) <= 0) {
/* Got error or connection closed by client */
if (numberOfBytesReceived == 0) {
/* Connection closed */
printf("Info: receiveMessageThread, node %d hung up\n", i);
}
else {
perror("Error: receiveMessageThread, recv FAILED\n");
}
close(i);
/* Remove from Master file descriptor set */
FD_CLR(i, &readFileDescriptorList);
doneReceiving = 1;
}
else {
/* Valid data from a node */
inMessage[6] = '\0';
if(++receiveCount == MAXIMUM_NUMBER_OF_NODES-1) {
doneReceiving = 1;
}
printf("ReceiveThread: %s received, count: %d\n", inMessage, rece iveCount);
}
}
}
}
pthread_exit(NULL);
}
Expected Output: I tried with just 2 processes, P1 (Started first) and P2 running on machine1 and another on machine2. Both the processes in the machines should first connect and then the threads should send and receive the message "Hello" and exit.
Observed Output: The P1 is able to send the message and P2 (receiver thread) is able to receive the message "Hello". But P1 (receiver thread) is not able to get the message from P2 (Sending thread). Application code is the same in both the machines but every time, the process started first does not get the message from the other process. I added a print to just check if some file descriptor was set, but I don't see it for P1 but only for the P2. The send in the receiving process is not failing, it returns with 6. I checked the maximum value of file descriptors, its correct.
If I start P2 first and then P1 then I can see that P1 receives the message from P2 and exists while P2 waits infinitely for the message from P1.
I am not sure if the problem is because of incorrect use of socket descriptors or because of threads ?
Two issues:
1 The loop testing for a file descriptor being set, does not include all file descriptors put into the set. (This programming error is expected to be the reason for the malfunction described in the OP.)
2 The sets of file descriptors passed to select() are modified by select(), so the set need to be re-initialized before for select() again. (The programming error would only be notable if from more than one socket data sall be received.)
Please see the following mod/s to the OP's code:
void *receiveMessageThread(void *pNodeInformation)
{
...
printf("ReceiveMessageThread: Receive thread created\n");
while(!doneReceiving) {
/* Initialize the read-set of file descriptors */
/* Issue 2 fixed from here ... */
FD_ZERO(&readFileDescriptorList);
for(i=0, iterNodeInformation=nodeInformation ; i<MAXIMUM_NUMBER_OF_NODES ; i++, iterNodeInformation++) {
FD_SET(iterNodeInformation->socketFd, &readFileDescriptorList);
if (iterNodeInformation->socketFd > fileDescriptorMax) {
fileDescriptorMax = iterNodeInformation->socketFd;
}
}
/* ... up to here. */
printf("ReceiveMessageThread: fileDescriptorMax:%d\n", fileDescriptorMax);
if (select(fileDescriptorMax+1, &readFileDescriptorList, NULL, NULL, NULL) == -1) {
perror("Error receiveMessageThread, select failed \n");
return -1;
}
for(i=0 ; i <= fileDescriptorMax ; i++) { /* Issue 1 fixed here. */
...
I have two daemons, and A is speaking to B. B is listening on a port, and A opens a tcp connection to that port. A is able to open a socket to B, but when it attempts to actually write said socket, I get a SIGPIPE, so I'm trying to figure out where B could be closing the open socket.
However, if I attach to both daemons in gdb, the SIGPIPE happens before any of the code for handling data is called. This kind of makes sense, because the initial write is never successful, and the listeners are triggered from receiving data. My question is - what could cause daemon B to close the socket before any data is sent? The socket is closed less than a microsecond after opening it, so I'm thinking it can't be a timeout or anything of the sort. I would love a laundry list of possibilities to track down, as I've been chewing on this one for a few days and I'm pretty much out of ideas.
As requested, here is the code that accepts and handles communication:
{
extern char *PAddrToString(pbs_net_t *);
int i;
int n;
time_t now;
fd_set *SelectSet = NULL;
int SelectSetSize = 0;
int MaxNumDescriptors = 0;
char id[] = "wait_request";
char tmpLine[1024];
struct timeval timeout;
long OrigState = 0;
if (SState != NULL)
OrigState = *SState;
timeout.tv_usec = 0;
timeout.tv_sec = waittime;
SelectSetSize = sizeof(char) * get_fdset_size();
SelectSet = (fd_set *)calloc(1,SelectSetSize);
pthread_mutex_lock(global_sock_read_mutex);
memcpy(SelectSet,GlobalSocketReadSet,SelectSetSize);
/* selset = readset;*/ /* readset is global */
MaxNumDescriptors = get_max_num_descriptors();
pthread_mutex_unlock(global_sock_read_mutex);
n = select(MaxNumDescriptors, SelectSet, (fd_set *)0, (fd_set *)0, &timeout);
if (n == -1)
{
if (errno == EINTR)
{
n = 0; /* interrupted, cycle around */
}
else
{
int i;
struct stat fbuf;
/* check all file descriptors to verify they are valid */
/* NOTE: selset may be modified by failed select() */
for (i = 0; i < MaxNumDescriptors; i++)
{
if (FD_ISSET(i, GlobalSocketReadSet) == 0)
continue;
if (fstat(i, &fbuf) == 0)
continue;
/* clean up SdList and bad sd... */
pthread_mutex_lock(global_sock_read_mutex);
FD_CLR(i, GlobalSocketReadSet);
pthread_mutex_unlock(global_sock_read_mutex);
} /* END for each socket in global read set */
free(SelectSet);
log_err(errno, id, "Unable to select sockets to read requests");
return(-1);
} /* END else (errno == EINTR) */
} /* END if (n == -1) */
for (i = 0; (i < max_connection) && (n != 0); i++)
{
pthread_mutex_lock(svr_conn[i].cn_mutex);
if (FD_ISSET(i, SelectSet))
{
/* this socket has data */
n--;
svr_conn[i].cn_lasttime = time(NULL);
if (svr_conn[i].cn_active != Idle)
{
void *(*func)(void *) = svr_conn[i].cn_func;
netcounter_incr();
pthread_mutex_unlock(svr_conn[i].cn_mutex);
func((void *)&i);
/* NOTE: breakout if state changed (probably received shutdown request) */
if ((SState != NULL) &&
(OrigState != *SState))
break;
}
else
{
pthread_mutex_lock(global_sock_read_mutex);
FD_CLR(i, GlobalSocketReadSet);
pthread_mutex_unlock(global_sock_read_mutex);
close_conn(i, TRUE);
pthread_mutex_unlock(svr_conn[i].cn_mutex);
pthread_mutex_lock(num_connections_mutex);
sprintf(tmpLine, "closed connections to fd %d - num_connections=%d (select bad socket)",
i,
num_connections);
pthread_mutex_unlock(num_connections_mutex);
log_err(-1, id, tmpLine);
}
}
else
pthread_mutex_unlock(svr_conn[i].cn_mutex);
} /* END for i */
/* NOTE: break out if shutdown request received */
if ((SState != NULL) && (OrigState != *SState))
return(0);
/* have any connections timed out ?? */
now = time((time_t *)0);
for (i = 0;i < max_connection;i++)
{
struct connection *cp;
pthread_mutex_lock(svr_conn[i].cn_mutex);
cp = &svr_conn[i];
if (cp->cn_active != FromClientDIS)
{
pthread_mutex_unlock(svr_conn[i].cn_mutex);
continue;
}
if ((now - cp->cn_lasttime) <= PBS_NET_MAXCONNECTIDLE)
{
pthread_mutex_unlock(svr_conn[i].cn_mutex);
continue;
}
if (cp->cn_authen & PBS_NET_CONN_NOTIMEOUT)
{
pthread_mutex_unlock(svr_conn[i].cn_mutex);
continue; /* do not time-out this connection */
}
/* NOTE: add info about node associated with connection - NYI */
snprintf(tmpLine, sizeof(tmpLine), "connection %d to host %s has timed out after %d seconds - closing stale connection\n",
i,
PAddrToString(&cp->cn_addr),
PBS_NET_MAXCONNECTIDLE);
log_err(-1, "wait_request", tmpLine);
/* locate node associated with interface, mark node as down until node responds */
/* NYI */
close_conn(i, TRUE);
pthread_mutex_unlock(svr_conn[i].cn_mutex);
} /* END for (i) */
return(0);
}
NOTE: I didn't write this code.
Is it possible you messed up and somewhere else in the program you try to close the same handle twice?
That could do this to you very easily.
HINT: systrace can determine if this is happening.
I have two nodes communicating with a socket. Each node has a read thread and a write thread to communicate with the other. Given below is the code for the read thread. The communication works fine between the two nodes with that code. But I am trying to add a select function in this thread and that is giving me problems (the code for select is in the comments. I just uncomment it to add the functionality). The problem is one node does not receive messages and only does the timeout. The other node gets the messages from the other node but never timesout. That problem is not there (both nodes send and receive messages) without the select (keeping the comments /* */).
Can anyone point out what the problem might be? Thanks.
void *Read_Thread(void *arg_passed)
{
int numbytes;
unsigned char *buf;
buf = (unsigned char *)malloc(MAXDATASIZE);
/*
fd_set master;
int fdmax;
FD_ZERO(&master);
*/
struct RWThread_args_template *my_args = (struct RWThread_args_template *)arg_passed;
/*
FD_SET(my_args->new_fd, &master);
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
int s_rv = 0;
fdmax = my_args->new_fd;
*/
while(1)
{
/*
s_rv = -1;
if((s_rv = select(fdmax+1, &master, NULL, NULL, &tv)) == -1)
{
perror("select");
exit(1);
}
if(s_rv == 0)
{
printf("Read: Timed out\n");
continue;
}
else
{
printf("Read: Received msg\n");
}
*/
if( (numbytes = recv(my_args->new_fd, buf, MAXDATASIZE-1, 0)) == -1 )
{
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("Read: received '%s'\n", buf);
}
pthread_exit(NULL);
}
You must set up master and tv before each call to select(), within the loop. They are both modified by the select() call.
In particular, if select() returned 0, then master will now be empty.