• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 359
  • Last Modified:

problem with socket in server

I have a server which allows a dedicated client to connect
and pass data back and forth. The server which I coded runs on Linux and the client an executable I didn't code, runs on windows. My problem is that when the server is stopped and restarted while the client is connected I sometimes have to wait about a minute before I can get them talking again by stopping both of them. I suspect that the socket is still alive and thinks a connection is still there until it times out or something. I close the server which is running as a thread by exiting a while loop when a ctrl-c key combination is pressed.
while(!quit), where quit is set to true when a ctrl-c
is pressed.
After I break the while loop condition, I've tried the following with no luck.

pthread_exit(0); the while no longer stops with this
or
exit(0); results in a segfault
or
close(socketFileDescriptor); has no effect

If I keep the server running and stop and start the client
it will reconnect but will no longer exchange data.

At this point I'm not sure if it's my code or the software I'm working with.

I have not set any socket options or have any code that removes sockets. I read that exit(0) should close all open file descriptors. The only thing I've used is
fcntl() to set the non_blocking option.

So I guess what my question comes down to is what is the proper way to gracefully shutdown a server running as a thread. Or have I tried the right things and the problem is not with my code?
Here is how I create the socket:

struct sockaddr_in server;
struct sockaddr_in client;
unsigned int serverDataLength, clientDataLength;
int serverSock_fd, client_fd;

serverSock_fd = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(5000);
serverDataLength = sizeof(server);
bind(serverSock_fd,(struct sockaddr * )&server
,serverDataLength);
listen(serverSock_fd,1);
clientDataLength = sizeof(client);
client_fd = accept(serverSock_fd,(struct sockaddr * )&client,&clientDataLength);
int flag = fcntl(client_fd,F_GETFL,0);
fcntl(client_fd,F_SETFL, O_NONBLOCK|flag);



0
mitchguy
Asked:
mitchguy
  • 7
  • 6
  • 2
  • +1
1 Solution
 
jhanceCommented:
Can I assume that you do not have access to the client code?
0
 
mitchguyAuthor Commented:
yeah I don't have any code for that. So I'm just trying to
make sure I get everything right on my end.
0
 
sevaCommented:
I think all you have to do on your end to terminate
gracefully is to close the client_fd.
This will initiate normal TCP connection termination sequence.
The client should call close on its end after
its "read" call returns 0.
if the client doesn't do this, then it's not your fault.
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
ambienceCommented:
>> I suspect that the socket is still alive and thinks a connection is still there until it times out or something

This usually happens when you set the SO_LINGER option.

Can you post the code where you are termination connections
0
 
mitchguyAuthor Commented:

Here is my termination connections

//server is a class
Server *object;
object = new Server();

I run this thread:

void *thread_func(void *arg){
object->startFileTransfer();
pthread_exit(0);
}

void Server::startFileTransfer(void){
while(!quit){
//processing code
}
close(serverSock_fd);
}

}
0
 
sevaCommented:
Another possibility is that the server cannot bind the socket because the address/port is still in use (because the old connection)
Try insert setsockopt with SO_REUSEADDR before bind()

const int     on = 1;

setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void*)&on, sizeof(on));
0
 
ambienceCommented:
closesocket(client_fd); ?? anywhere ?
0
 
mitchguyAuthor Commented:
using:
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,(const void* &on, sizeof(on));
solved half of my problem.
With the client running continuously trying to connect with the server. I can start and stop the server at will and the client connects and I don't have to wait.

My only problem now is if the Server is continuously running and after the client connects I stop the client, the server crashes with the message "broken pipe"
so I can't stop and start the client with the Server Continuosly.
I do also have
closesocket(client_fd);
 

0
 
sevaCommented:
Can you post your code for the server with more details,
better all the server code?
From what is already there, it seems that you
are not calling accept inside the while loop.
0
 
mitchguyAuthor Commented:
I don't have my accept call in the while loop.
That is an obvious mistake on my part. I think I originally
put it in there and it wasn't working properly so I moved it out. After putting it back in the while loop it does
connect and disconnect with out crashing the server, but It
hangs before the accept call the second time through the
loop. So The processing stops.
createSocket(){
struct sockaddr_in server;
struct sockaddr_in client;
unsigned int serverDataLength, clientDataLength;
int serverSock_fd, client_fd;

serverSock_fd = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(5000);
serverDataLength = sizeof(server);
bind(serverSock_fd,(struct sockaddr * )&server
,serverDataLength);
listen(serverSock_fd,1);
clientDataLength = sizeof(client);
}

startServer(){
 createSocket();
 
while(!quit){

client_fd = accept(serverSock_fd,(struct sockaddr * )&client,&clientDataLength);
int flag = fcntl(client_fd,F_GETFL,0);
fcntl(client_fd,F_SETFL, O_NONBLOCK|flag);
read(client_fd,&buf,sizeof(buf));
processMsg(buf);
}
}
0
 
sevaCommented:
Does your client follow request-response pattern,
creating a new connection for every data transfer?

Also, you set the socket to be non-blocking,
then, you need to handle all different cases for the read()
call, such as read() returns because it would block
(no data available), read() returns some data < sizeof(buf)
etc.
You need to somehow know how much data the client sends
and make another "while" loop around read() until the server reads that much data.
After you are done with the request, you need to close
client_fd at the end of the loop, before going back to
accept().

0
 
mitchguyAuthor Commented:
The connection is meant to stay active once made
until the session is over so a new connection is not
made for every data transfer.
For my program there is only one client that is
allowed to connect at any given time. Once the connection
is made the client starts sending messages of all types
and sizes each at different time intervals most at 4 per second, until the session is over.
The buffer is big enough to hold all messages that are
sent from the client for each read.

I've specified the socket to have allow one connection
at a time with listen(serverSock_fd,1); since there is only one possible client.

so once the client connects and I get my client
socket file descriptor I try to read that file
descriptor. It gets set from the return value
of accept.

what happens to the accept function call while
the client is connected the second time through the loop. Does it still get called
and reset the file Descriptor so my read call no
longer reads a valid file descriptor?
0
 
sevaCommented:
OK, then you need to move accept() before the "while".
accept() takes the first availble incoming TCP
connection and creates a new socket for it.

However, you still have a problem with not knowing
how much data the client sends. read() may return
-1 with errno==EWOULDBLOCK if there is no data available,
or it may return any number of bytes that is ready,
but not necessary all bytes that client sent.
0
 
mitchguyAuthor Commented:
It's true I don't know exactly how much data will
be there for any given read() and sometimes it was returning -1 , but it wasn't blocking.
I was printing out the bytes read and saw the -1
so I added this:
int bytes_read = read(...);
if (bytes_read > 0){
processMsg(buf);
}

I suppose the NON_BLOCKING flag allowed me to continue
reading.

So if I have the accept() outside of the while loop.
and the client disconnects and then trys to reconnect
,since I don't have an accept() call in the while loop
it should fail right?
If closing the file descriptor is what's necessary when the client disconnects, how can the server know when the
connection is closed.
I was thinking if I put the accept() call in the while loop
, but only called it when I know there isn't a connection
active.
something like the following.
bool connected = false;

if(!connected){
accept();
connected = true;
}

If I know when a connection is closed I could set connection = false;

Do you think this would work?
is there a way to know when the connection is closed?

 
0
 
sevaCommented:
A connection is closed when read() returns 0.
Also, you may want to check the errno when read()
returns -1.
If errno==EWOULDBLOCK, then it's fine since
read() returned because no data availble.
If errno != EWOULDBLOCK, then an error occured.

It may work, though in general it is not a good design.
Your server continuosly loops around wasting CPU time.
A better solution might be to use select().
0
 
mitchguyAuthor Commented:
I think you've given me enough information to solve all of
my problems tomorrow.
Thanks
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

  • 7
  • 6
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now