I'm trying to figure out what is blocking my program. I'm running a server that uses POSIX threads. I have to for my computer programming lab. The main function listens for new connections. Once it accepts a connection, it creates a new thread by passing the FD to the thread. I'm able to successfully connect to the server using multiple telnet/client connections. I can send data to the server successfully once, but if I try sending again the server won't do anything.
Part of the main function
int active_thread = 0;
//The Running loop
while(running)
{
if(active_thread > NUMBTHREADS)
{
printf("Unable to accept client connection! Threads are all used up");
running = false;
}
else
{
if(FD_ISSET(sockfd, &readfds))
{
if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1)
{
fprintf(stderr, "Unable to accept client \n");
perror("What");
break;
}
activethreads[active_thread] = pthread_create( &threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]);
//close(bindfd[active_thread]);
//pthread_join( threads[active_thread], NULL);
active_thread++;
//running = false;
}
}
}
close(sockfd);
return 0;
}
Part of the POSIX THREAD CODE
void *server_handler( void *sockfd)
{
int bindfd = *( (int *) sockfd);
char buffer[MESSAGELENGTH];
bool running = true;
printf("Thread was created successfully\n");
char intro[] = "Successfully Connected to server!\n";
struct pollfd pfd;
pfd.fd = bindfd;
pfd.events = POLLIN;
if ( (send(bindfd, intro, strlen(intro), 0)) < 0)
{
perror("Unable to send");
}
while(running){
char msg[] = "\nYou have the following options!\n1) Insert an integer: insert <integer>\n2) Remove An Integer: remove <integer>\n3) Get number of integers in list: get_count\n4) Get first integer: get_first\n5) Get last integer: get_last\n6) Quit program: quit\n ";
if ( (send(bindfd, msg, strlen(msg), 0)) < 0)
{
perror("Unable to send");
}
memset(&buffer, 0, MESSAGELENGTH);
if (recv(bindfd, buffer, MESSAGELENGTH, 0) > 0)
{
//SOme other code
}
}
I think its blocking at either the accept or recv. I've heard of select() and various other methods, but I'm having difficulty trying to implement them. Thanks!
The root cause of your issue appears to be that you are unconditionally executing close(sockfd); return 0; at the bottom of your while (running) loop, which means that the loop only ever executes once.
Additionally, you should not be using FD_ISSET() unless you are also using select(). Your main loop should look something more like:
int active_thread = 0;
while (active_thread < NUMBTHREADS)
{
if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1)
{
fprintf(stderr, "Unable to accept client \n");
perror("What");
break;
}
activethreads[active_thread] = pthread_create( &threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]);
active_thread++;
}
if (active_thread >= NUMBTHREADS)
{
printf("Unable to accept client connection! Threads are all used up.\n");
}
running = false;
close(sockfd);
return 0;
By default network sockets are blocking. You need to set the O_NONBLOCK flag on the socket.
if(fcntl(fd, F_GETFL, &flags) < 0 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
perror("Failed to set socket as non-blocking");
Now, instead of blocking when there is no input (or buffer space to store output), the error EAGAIN (or EWOUDLBLOCK) is returned. Lastly, you will need to use select() or poll() when you have nothing else to do but wait on I/O. These calls will only wake the process when either there is input, room for output, or possibly a time-out period passes.
int maxFd;
fdset fds;
FD_ZERO(&fds);
FD_SET(listenFd, &fds);
FD_SET(sockFd1, &fds);
FD_SET(sockFd2, &fds);
maxFd = listenFd+1;
maxFd = sockFd1 > maxFd ? sockFd1+1 : maxFd;
maxFd = sockFd2 > maxFd ? sockFd2+1 : maxFd;
if(select(maxFd, &fds, &fds, &fds, NULL) < 0) {
perror("Failed on select()");
exit(1);
}
if(FD_ISSET(listenFd, &fds))
...
This example is not complete or neccessarily 100% correct, but should be a good start. Also, I tend to reserve using send*() and recv*() when dealing with SOCK_DGRAM sockets and just use read(), write() on SOCK_STREAM sockets.
Related
Is using alarm() is the only to set connect() timeout on unix domain socket? I've tried select() which is described here but seems like select() returns ok immediately on unix domain socket every time and
no error occurred by calling getsockopt(SO_ERROR), but a send() on the fd returns an error says Transport endpoint is not connected. I paste the select() code below.
I think using alarm would meet the case, but seems it's considered as an old-fashion way. So I'm here to see if there's any other solutions for this. Thanks in advance.
if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
syslog(LOG_USER|LOG_ERR, "fcntl get failed: %s", strerror(errno));
close(fd);
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
syslog(LOG_USER|LOG_ERR, "set fd nonblocking failed: %s", strerror(errno));
close(fd);
return -1;
}
if(connect(fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINPROGRESS) {
close(fd);
return -1;
}
FD_ZERO(&set);
FD_SET(fd, &set);
if(select(fd + 1, NULL, &set, NULL, &timeout) <= 0) {
close(fd);
return -1;
}
/*
if(connect(fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0) {
close(fd);
return -1;
}
*/
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len) < 0) {
syslog(LOG_USER|LOG_ERR, "getsockopt failed: %s", strerror(errno));
close(fd);
return -1;
}
if(error != 0) {
syslog(LOG_USER|LOG_ERR, "getsockopt return error: %d", error);
close(fd);
return -1;
}
}
if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1) {
syslog(LOG_USER|LOG_ERR, "set fd blocking failed: %s", strerror(errno));
close(fd);
return -1;
}
Somewhere (I did not bookmark that page) in another post I found that the connect() only establishes a TCP connection. It only means that on the other end, there is a working TCP stack, but it does not mean, the server has actually accept()-ed!
The example there was connect() is like calling a support center, and the automatic voice tells you, you are in a queue, but you still cannot communicate. accept() is the actual operator taking your call.
My solution for the same problem will be to have the client wait for the server to actually send something, before moving on with other client-stuff. I can put this in a select-timeout loop.
listen() has a parameter, how many connections can be put in a backlog before starting to drop client connection attempts.
You can use select() or poll() after EINPROGRESS, as described in the connect man page. If you get EAGAIN or EWOULDBLOCK, the Unix domain socket has run out of backlog entries, the queue length specified by the server with the listen() call. The connect() failed.
Note that a connecting client can be able to write to Unix domain sockets until the system buffer is full, before the server even accepted the call. That works for each backlog buffer. Failures occur afterwards.
A failed connect() might need a new socket before retrying. select() might return 0 also if the connection was refused, such as if the server didn't listen(). That depends on system and libray. At any rate, after an error of EAGAIN, it is necessary to retry. For example:
int rtc, so_error, max_retry = 5;
socklen_t len = sizeof so_error;
while ((rtc = connect(fd, (struct sockaddr *)&address, sizeof address)) != 0
&& errno == EAGAIN && --max_retry >= 0) {
sleep(1);
// new socket?
}
if (rtc < 0 && errno != EINPROGRESS) {
syslog(LOG_USER|LOG_ERR, "connect returned %d: %s", rtc, strerror(errno));
close(fd);
return -1;
}
if (rtc < 0)
{
fd_set set, wset, eset;
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
FD_ZERO(&set);
FD_SET(fd, &set);
wset = set;
eset = set;
if(select(fd + 1, &set, &wset, &eset, &timeout) <= 0) {
close(fd);
return -1;
}
// [...]
}
The program creates n threads for simulating n nodes in a distributed system, each has one socket it listens to and each thread can communicate to n-1 other threads through connect calls.
Each thread makes a call to select() to see if anything's available and if so accepts and saves the data.
I use ioctl with the flag FIONREAD to check the number of bytes available to be read and do an appropriate read call. Afterwards the new fd (from accept()) is closed.
The listening sockets are blocking. O_NONBLOCK is NOT set.
All n threads run the same function. All variables declared within the function use thread local storage.
There's no explicit synchronization done on my part. More than one thread can try to connect to the same socket at once.
Now, the problem is, once in a while, the select() in a thread on the receiving side notes something new but the amount of bytes available is 0 which it shouldn't be. This happens inconsistently.
Would be great if someone can point where I should look into. Thanks!
creating the sock
if ( (nptr->sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
fd_max = nptr->sock > fd_max ? nptr->sock : fd_max;
int ok=1;
setsockopt(nptr->sock, SOL_SOCKET, SO_REUSEADDR, &ok, sizeof(int));
nptr->addr.sun_family = AF_UNIX;
snprintf(nptr->addr.sun_path, 20, "%d", nptr->id);
//strncpy(nptr->addr.sun_path, sock_path, 20);
if ( bind(nptr->sock, (struct sockaddr*)&(nptr->addr), sizeof(struct sockaddr_un)) < 0 ) {
perror("bind");
exit(1);
}
/* socket, max connections */
if ( listen(nptr->sock, 2*tot_node) < 0 ) {
perror("listen");
exit(1);
}
sending stuff
for (t=0; t<tot_node; t++) {
...
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
printf("Node %d: trying to req node %d... ", self->id, node_catalog[t]->id);
if ( connect(fd, (struct sockaddr*)&(node_catalog[t]->addr), sizeof(struct sockaddr_un)) == -1 ) {
perror("connect");
exit(1);
}
buf[0] = TYPE_REQ;
buf[1] = self->id;
buf[2] = ts;
buf[3] = rsc;
write (fd, buf, 4*sizeof(int));
//close(fd);
printf("Node %d: sent req for resource %d to %d\n", self->id, rsc, node_catalog[t]->id);
}
usleep(TS_UPDATE_ITV);
receiving stuff
FD_ZERO(&readset);
FD_SET(self->sock, &readset);
t = pselect(self->sock+1, &readset, NULL, NULL, &tout, NULL);
if (t > 0 && FD_ISSET(self->sock, &readset)) {
com_fd = accept(self->sock, NULL, NULL);
ioctl(com_fd, FIONREAD, &t);
#ifdef DEBUG
printf(" Node %d: received %d bytes of data\n", self->id, t);
#endif
read(com_fd, buf, t);
close(com_fd);
dptr = (int *)buf;
rsc = t / (sizeof(int)); /* var reuse. this is the count of ints to read */
for (t=0; t<rsc; ) {
static __thread int nid, nts, nrsc;
#ifdef DEBUG
printf(" Node %d: data rcvd: %d %d %d %d", self->id, *dptr, *(dptr+1), *(dptr+2), *(dptr+3));
#endif
if (*dptr == TYPE_REQ) {
... } else {...}
Your code doesn't make sense. The reason that select() fired was that there was something to accept. Checking FIONREAD on a socket you've just accepted may or may not result in data being available. It depends entirely on whether the client has sent any. Not on the contract of select().
If you need to know whether there is something to read, you should add the accepted socket to the read-FD set, and process it in a loop: if the listening socket is readable, call accept() on it, otherwise it is an accepted socket and you should call read() on it.
Checking FIONREAD is really just a waste of time in most circumstances.
I will elaborate as much as possible without being too lengthy about the issue I would like help with, if possible:
I'm writing a program that communicates with two sockets, I listen on the multicast socket, while I delegate to the other socket "Unicast" important information stemming from the communicated data coming from the first socket "Multicast".
There are two issues that I think they are related:
1- I run the program in one comuputer "Linux" communicating to another "Linux", and the program performs as expected. But when i take it to another computer "running both my program and the other programs, all in one host" with similar Multicast configuration, I get the following error:
Select : Interrupted system call
This is a perror message, but i am not sure if it is due to error in select() or my multicast configuration.
2- As a result of the first issue, I am unable to delegate to the "Unicast" client socket, but the Unicast works because there is some periodic checking between "Unicast client" and my program running all the time.
My code is as a follow:
struct ConfigStruct
{
struct sockaddr_in Hinfo1, Hinfo2;
struct sockaddr_in Rinfo;
int sock1, sock2;
};
int main()
{
ConfigStruct StructArg;
int fd1, fd2;
int POS(1);
/****************** Network parameters declaration *************************/
// Declaration for socket addresses
struct sockaddr_in Host_info1, Host_info2;
struct sockaddr_in Remote_info;
struct in_addr localInterface;
struct ip_mreq Group;
memset((char *)&Host_info1,0,sizeof(Host_info1));
memset((char *)&Host_info2,0,sizeof(Host_info2));
memset((char *)&Remote_info,0,sizeof(Remote_info));
memset((char *)&Group,0,sizeof(Group));
//**** Reads configuration file****************
cout<<"Reading configuration file..........."<<endl;
std::string input1 ="192.***.**.**";
std::string input2 = "8888";
std::string input3 ="192.***.**.**";
std::string input4 = "8889";
const char* addr_input = input1.data();
const char* port_input = input2.data();
const char* addr_input2 = input3.data();
const char* port_input2 = input4.data();
Remote_info.sin_addr.s_addr=inet_addr(addr_input);
Remote_info.sin_port = htons((uint16_t)stoi(port_input,nullptr,0));
Remote_info.sin_family=AF_INET;
Host_info1.sin_addr.s_addr=inet_addr(addr_input2);//htonl(INADDR_ANY);
Host_info1.sin_port = htons((uint16_t)stoi(port_input2,nullptr,0));
Host_info1.sin_family=AF_INET;
//***** First socket *******
fd1= socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if (fd1 == -1)
{
std::cout<<"A problem occured"<<endl;
cease("socket", wd) ;
}
if (setsockopt(fd1,SOL_SOCKET,SO_REUSEADDR, &POS, sizeof(POS)) == -1)
{
perror(" Error in setsockopt");
exit(1);
}
// **** I'M NOT SURE IF THIS NECESSARY **************
int opts;
opts = fcntl(fd1,F_GETFL);
if (opts < 0)
{
perror("fcntl(F_GETFL)");
exit(EXIT_FAILURE);
}
opts = (opts | O_NONBLOCK);
if (fcntl(fd1,F_SETFL,opts) < 0)
{
perror("fcntl(F_SETFL)");
exit(EXIT_FAILURE);
}
//*****************************************************
if (bind(fd1,(struct sockaddr *)&Host_info1,sizeof(Host_info1)) < 0)
{
cease("Bind",wd);
}
else
{
cout<<" Socket ID number "<<fd1<<endl;
cout<<" Bound socket..."<<endl;
}
//********** The multicast network setup ***********************
std::string input5 ="230.*.**.**";
std::string input6 = "192.***.***"; // The same host IP address as above
std::string input7 = "1500" ; // The port number to listen to for Multicast message
const char* Group_Multi_Addr = input5.data();
const char* Group_Interface_Addr = input6.data();
const char* Host_port_input = input7.data();
Group.imr_multiaddr.s_addr = inet_addr(Group_Multi_Addr);
Group.imr_interface.s_addr = inet_addr(Group_Interface_Addr);
Host_info2.sin_family = AF_INET;
Host_info2.sin_addr.s_addr = INADDR_ANY;
Host_info2.sin_port = htons((uint16_t)stoi(Host_port_input,nullptr,0));
//***** The second socket *******
fd2 = socket(AF_INET, SOCK_DGRAM, 0);
if(fd2 < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening the datagram socket...OK.\n");
int reuse = 1;
if(setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
close(fd2);
cease("Setting SO_REUSEADDR error", wd);
}
else
printf("Setting SO_REUSEADDR...OK.\n");
if(bind(fd2, (struct sockaddr*)&Host_info2, sizeof(Host_info2)))
{
close(fd2);
cease("Binding datagram socket error",wd);
}
else
printf("Binding datagram socket...OK.\n");
if(setsockopt(fd2, IPPROTO_IP, IP_ADD_MEMBERSHIP,(char *)&Group,sizeof(Group)) < 0)
{
perror("Adding multicast group error");
close(fd2);
exit(1);
}
else
printf("Adding multicast group...OK.\n");
StructArg.Hinfo1= Host_info1;
StructArg.Hinfo2= Host_info2 ;
StructArg.Rinfo= Remote_info ;
StructArg.sock1=fd1;
StructArg.sock2=fd2;
fd_set readfds ,rd_fds;
struct timeval tv;
// clear the set ahead of time
FD_ZERO(&readfds);
// add our descriptors to the set
FD_SET(StructArg.sock1, &readfds);
FD_SET(StructArg.sock2, &readfds);
nls = StructArg.sock2 + 1;
tv.tv_sec = 0;
tv.tv_usec = 50;
char Recv_buffer[125];
char TX_buffer[125];
memset((char *)&Recv_buffer,'0',sizeof(Recv_buffer));
memset((char *)&TX_buffer,'0',sizeof(TX_buffer));
int lenremote(sizeof(StructArg.Rinfo));
ssize_t rs, rs2;
uint8_t MsgSize;
uint8_t MsgID;
do
{
rd_fds=readfds;
if (select(nls, &rd_fds, NULL, NULL, &tv) < 0)
{
perror("select"); // error occurred in select()
}
else
{
// one or both of the descriptors have data
if (FD_ISSET(StructArg.sock1, &rd_fds))
{
rs = recvfrom(StructArg.sock1,....,...,0,...,...) ;
if ( rs > 0 )
{
Do bunch of routines
}
}
if (FD_ISSET(StructArg.sock2, &rd_fds))
{
rs2 = recv(StructArg.sock2,&Recv_buffer,sizeof(Recv_buffer),0);
if ( rs2 > 0 )
{
send some data to StructArg.sock1
}
}
// I do some work here , i send somethings to Sock 1 (Is this appropriate ??)
}
while(1);
return 0;
}
So most importantly, why do I get Select : System interrupt call in one computer but not another?
I am not sure if it is due to error in Select() or my multicast configuration.
Neither. It is due to a signal being caught during the system call. Just loop around this condition, eg:
do
{
// ...
rc = select(nls, &rd_fds, NULL, NULL, &tv);
} while (rc == -1 && errno == EINTR);
if (rc == -1)
{
perror("select");
}
else
{
// ...
}
most importantly, why do i get , Select : System interrupt call in one computer but not another
Because you got a signal on one computer and not the other. And it isn't important.
how about the timeouts, because the man page, says that timeout
becomes undefined when an error arise, should i put the tv.sec and
tv.usec inside the loop.
man 2 select:
On Linux, select() modifies timeout to reflect the amount of time not
slept; most other implementations do not do this. (POSIX.1-2001
permits either behavior.)
On Linux thus, the code shown in the question probably doesn't act as intended, because the timeout is set before the loop only once and zeroed if it expires - from then on, it remains zero. Here, it would be appropriate to set the desired timeout inside the main loop, but outside the proposed loop … while (rc == -1 && errno == EINTR).
On systems that don't update timeout accordingly, there is in the presence of interruptions no such easy way to maintain the correct timeout.
I have a simple server that in a separate thread waits for a network connection and then sends information periodically to the client. The main thread accepts commands via stdin. What I don't understand is why stdin receives EOF when the client is terminated.
For the sample code below, the client can be as simple as 'nc 127.0.0.1 1234' in the command line. When the client is interrupted with 'kill' or Ctl-C the server exits due to EOF on stdin. I'd certainly appreciate an explanation for this behavior and a workaround that keeps the server running.
static void *WaitForConnections(void *p) {
int sockfd, newsockfd;
struct sockaddr_in server = { sizeof(server), AF_INET, htons(1234), INADDR_ANY};
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket call failed");
exit(1);
}
if ( bind(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1){
perror("bind call failed");
exit(1);
}
if ( listen(sockfd, 0) == -1 ) {
perror("listen call failed");
exit(1);
}
for (;;) {
if ( (newsockfd = accept(sockfd, NULL, NULL)) != -1) { // new connection
for ( ;;) {
char c = 'd';
if (send(newsockfd, &c, sizeof(c), 0) != sizeof(c)) {
break;
}
sleep(1);
}
close(newsockfd);
}
else {
break;
}
}
close(sockfd);
return NULL;
}
int main(int argc, const char * argv[]) {
pthread_attr_t attr;
pthread_t p;
void * status;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (0 != pthread_create( &p, &attr, WaitForConnections, NULL )) {
fprintf(stderr, "thread creation failed\n");
exit(1);
}
while (getchar() != EOF) {}
pthread_join(p, &status);
return 0;
}
It shouldn't matter, but this is under MacOS X 10.10.1, Xcode 6.1.1 and Apple LLVM 6.0.
Your server doesn't exit because of EOF on stdin, it exits because it tries to send data on a broken TCP connection, which causes the SIGPIPE signal to be delivered - and the default action for SIGPIPE is to terminate the process.
You should ignore SIGPIPE with
signal(SIGPIPE,SIG_IGN);
And that will cause send()/write() calls to instead return -1 and set errno to EPIPE, which your code can handle.
when I close my client connected to the server I get this error from the server and server shuts itself down. I know that client can terminate the connection gracefully but I am planning to send this out to some people and do not want my server to be shut just because they did not terminate gracefully. So what could actually prevent the server to be closed?
I am using sys/socket.h
Here's a part of my code
int server() {
//Set up variables
int sockfd, new_fd; //Listen on sock_fd, new connection on new_fd
struct sockaddr_in my_addr; //My(server) address information
struct sockaddr_in their_addr; //Connector's address information
socklen_t sin_size;
//Generate the socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
//Generate the end point
my_addr.sin_family = AF_INET; //Host byte order
my_addr.sin_port = htons(MYPORT); //Short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; //Auto-fill with my IP
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind");
exit(1);
}
//Start listnening
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
while(TERMINATE == 0) { // main accept() loop
sin_size = sizeof(struct sockaddr_in);
//Create a new connection for the accepted socket
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
perror("accept");
continue;
}
//some semaphore stuff
}
return 0;
}
int main(int argc, char *argv[]){
//extra stuff
//Set up mutex locks
pthread_mutex_init(&mutex, NULL);
sem_init(&empty, 0, 30);
sem_init(&full, 0, 0);
//Set up and run Threads
pthread_t threads[30]; //Array of threads
pthread_t server_thread;
pthread_attr_t attr; //Set of thread attributes
//Get the default thread attributes
pthread_attr_init(&attr);
signal(SIGINT, termination);//Wait for a SIGINT
//Loop to create threads and execute consumer_thread
for (int i = 0; i < 30; i++) {
//Set up data in structure
threadArray[i].threadID = i;
threadArray[i].running = 0;
threadArray[i].line_counter_pointer = &line_counter;
threadArray[i].vid_details_pointer = &vid_details;
pthread_create(&threads[i],&attr,consumer_thread, &threadArray[i]);
}
//Execute the producer_thread
pthread_create(&server_thread,&attr,producer_thread, NULL);
//Wait for all the threads to exit
for (int i = 0; i < 30; i++) {
pthread_join(threads[i],NULL);
}
//Destroy semaphores so that it can TERMINATE gracefully
sem_destroy(&empty);
sem_destroy(&full);
return 0;
}
void *producer_thread(void *param) {
server();//Runs the server() function
return NULL;
}
void *consumer_thread(void *param) {
//Pass variable
struct thread_params *threadStruct;
threadStruct = (struct thread_params *) param;
int *line_counter = threadStruct->line_counter_pointer;
vid_details_struct *vid_details = threadStruct->vid_details_pointer;
//End of pass
char found_result [MAXDATASIZE];
int queue_item = 0;
int numbytes;
struct timeval item_wait_time;// Get the current time
while (TERMINATE == 0) { //Main accept() loop
int new_fd;
//Use a variable that would be set to 0 after the client termination
//so that the current connection will be closed on both thread and
//client, that would make thread to go back to idle
int current_connection = 1;
//Acquire full semaphore
sem_wait(&full);
//Acquire mutex lock to protect buffer
pthread_mutex_lock(&mutex);
//some extra stuff including socket information
//now handling queue[queue_item]
new_fd = queue[queue_item].new_fd;
queue[queue_item].waiting = 0;
//Release mutex lock and empty semaphore
pthread_mutex_unlock(&mutex);
sem_post(&empty);
while (current_connection == 1) {
char buf[MAXDATASIZE];
//Receive the query
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';//Set the end point of the string
if (!strcmp(buf,"q")) {//Client prompts to TERMINATE
current_connection = 0;//Flag the connection as closed
}
if (current_connection == 1) {//If still connected
//do something
if (send(new_fd, found_result, MAXDATASIZE, 0) == -1) {
perror("send");
close(new_fd);
exit(0);
}
}
}
close(new_fd); // Close the socket connection
//Wait for half a second before accepting a new request
usleep(500000);
}//End of the main while loop
FINISHEDSEMS++;
printf("Thread %d is closing\n", threadStruct->threadID);
return NULL;
}
This if-statement is what you need to look at:
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv");
exit(1);
}
It's the only place you posted that has recv, so that's the error.
Take a look at the man page: recv returns the length of the message on successful completion. If a message is too long to fit in the supplied buffer, excess bytes may be discarded depending on the type of socket the message is received from. If no messages are available at the socket, the receive calls wait for a message to arrive, unless the socket is nonblocking (see fcntl(2)), in which case the value -1 is returned and the external variable errno is set
So instead of having a call to exit (which terminates the process), try handling the error gracefully:
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) < 0) {
// user disconnected or timeout (if you set a timeout)
// NO call to exit; use "continue" or "return", or something else
// to gracefully handle the break;
my_error_function("client disconnected\n");
break;
}
'Connection reset by peer' has a number of causes, but the most common one is that you have written to a connection that has already been closed by the peer. In other words, an application protocol error.