Solved

problem with socket in server

Posted on 2002-04-30
16
323 Views
Last Modified: 2008-02-01
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
Comment
Question by:mitchguy
  • 7
  • 6
  • 2
  • +1
16 Comments
 
LVL 32

Expert Comment

by:jhance
Comment Utility
Can I assume that you do not have access to the client code?
0
 

Author Comment

by:mitchguy
Comment Utility
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
 
LVL 1

Expert Comment

by:seva
Comment Utility
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
 
LVL 22

Expert Comment

by:ambience
Comment Utility
>> 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
 

Author Comment

by:mitchguy
Comment Utility

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
 
LVL 1

Expert Comment

by:seva
Comment Utility
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
 
LVL 22

Expert Comment

by:ambience
Comment Utility
closesocket(client_fd); ?? anywhere ?
0
 

Author Comment

by:mitchguy
Comment Utility
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
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 1

Expert Comment

by:seva
Comment Utility
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
 

Author Comment

by:mitchguy
Comment Utility
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
 
LVL 1

Expert Comment

by:seva
Comment Utility
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
 

Author Comment

by:mitchguy
Comment Utility
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
 
LVL 1

Expert Comment

by:seva
Comment Utility
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
 

Author Comment

by:mitchguy
Comment Utility
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
 
LVL 1

Accepted Solution

by:
seva earned 150 total points
Comment Utility
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
 

Author Comment

by:mitchguy
Comment Utility
I think you've given me enough information to solve all of
my problems tomorrow.
Thanks
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now