Hey all, I'm about to rip my hair out. I have this client that tries to connect to a server, everything seems to be fine, using gethostbyname(), socket(), bind(), but when trying to connect() it just hangs there and the server doesn't see anything from the client. I know that the server works because another client (also in C) can connect just fine. What causes the server to not see this incoming connection? I'm at the end of my wits here. The two different clients are pretty similar too so I'm even more lost.
if (argc == 2) {
host = argv[1]; // server address
}
else {
printf("plz read the manual\n");
exit(1);
}
hserver = gethostbyname(host);
if (hserver) {
printf("host found: %p\n", hserver);
printf("host found: %s\n", hserver->h_name );
}
else {
printf("host not found\n");
exit(1);
}
bzero((char * ) &server_address, sizeof(server_address)); // copy zeroes into string
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(hserver->h_addr);
server_address.sin_port = htons(SERVER_PORT);
bzero((char * ) &client_address, sizeof(client_address)); // copy zeroes into string
client_address.sin_family = AF_INET;
client_address.sin_addr.s_addr = htonl(INADDR_ANY);
client_address.sin_port = htons(SERVER_PORT);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
exit(1);
else {
printf("socket is opened: %i \n", sockfd);
info.sock_fd = sockfd;
rv = fcntl(sockfd, F_SETFL, O_NONBLOCK); // socket set to NONBLOCK
if(rv < 0)
printf("nonblock failed: %i %s\n", errno, strerror(errno));
else
printf("socket is set nonblock\n");
}
timeout.tv_sec = 0; // seconds
timeout.tv_usec = 500000; // micro seconds ( 0.5 seconds)
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
rv = bind(sockfd, (struct sockaddr *) &client_address, sizeof(client_address));
if (rv < 0) {
printf("MAIN: ERROR bind() %i: %s\n", errno, strerror(errno));
exit(1);
}
else
printf("socket is bound\n");
rv = connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
printf("rv = %i\n", rv);
if (rv < 0) {
printf("MAIN: ERROR connect() %i: %s\n", errno, strerror(errno));
exit(1);
}
else
printf("connected\n");
Any thoughts or insights are deeply greatly humongously appreciated.
-Fourier
EDIT:
If the socket is NOT set on non-block, then it hangs.
If the socket is set on non-block, then I get ERROR connect() 115: Operation now in progress
[EINPROGRESS]
O_NONBLOCK is set for the file descriptor for the socket and the connection cannot be immediately established; the connection shall be established asynchronously.
I would also like to mention that the server and the client are running on computers next to each other, connected by like one router.
The gethostbyname() function produces addresses in network byte order, so you do not need to pass them through htonl(). Also, the hostent->h_addr entry is a pointer to the address. Replace this line:
server_address.sin_addr.s_addr = htonl(hserver->h_addr);
with:
memcpy(&server_address.sin_addr, hserver->h_addr, hserver->h_length);
I see you set your socket in O_NONBLOCK mode.
Thus connect must return -1 and set errno to EAGAIN according to the man page of connect.
You can then know when the connection succeeded using select() on the socket.
This is a very common pattern to control the connection timeout (because select() must be feed with a timeout).
Check whether you can connect with the program telnet (it accepts a server name and port number). If that works, the bug must be in your code. If telnet also hangs, then check your firewall settings.
If you want to connect twice from the same machine I can see the reason for your problem.
You are binding the clientsocket. Your code binds the client socket very specifically to a fixed port (the server port). This leaves the O/S NOT free in choosing an available port for making the connection FROM. If one process has the port allocated (it has succesfully bound() and connected() to the server) then the other process cannot use that same port.
If there is no compelling reason for sending traffic FROM a specific port, let the O/S find an available port by changing this line
client_address.sin_port = htons(SERVER_PORT);
to
client_address.sin_port = 0;
Related
I am trying to write a basic TCP server that streams serial data to a client. The server would connect to a serial device, read data from said device, and then transmit it as a byte stream to the client. Writing the TCP server is no problem. The issue is that the server will crash when a client disconnects. In other languages, like Python, I can simply wrap the write() statement in a try-catch block. The program will try to write to the socket, but if the client has disconnected then an exception will be thrown. In another project, this code snippet worked for me:
try:
client_socket.send(bytes(buf, encoding='utf8'))
except Exception as e:
logger.info("Client disconnected: %s", client_id)
I can handle client disconnects in my C code, but only by first reading from the socket and checking if the read is equal to 0. If it is, then my client has disconnected and I can carry on as usual. The problem with this solution is that my client has to ping back to the server after every write, which is less than ideal.
Does anyone know how to gracefully handle TCP client disconnects in C? My example code is shown below. Thank you!
// Define a TCP socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
// Allow for the backlog of 100 connections to the socket
int backlog = 100;
// Supply a port to bind the TCP server to
short port = 9527;
// Set up server attributes
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
// Set the socket so that we can bind to the same port when we exit the program
int flag = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1) {
perror("setsockopt fail");
}
// Bind the socket to the specified port
int res = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (res < 0) {
perror("bind fail");
exit(1);
}
// Listen for incoming connections
if (listen(sockfd, backlog) == -1) {
perror("listen fail");
exit(1);
} else {
printf("Server listening on port\n", port);
}
for(;;) {
// Wait for incoming connection
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len);
if (-1 == connfd) {
perror("Could not accept incoming client");
continue;
}
//Resolving Client Address
char buff[INET_ADDRSTRLEN + 1] = {0};
inet_ntop(AF_INET, &cliaddr.sin_addr, buff, INET_ADDRSTRLEN);
uint16_t cli_port = ntohs(cliaddr.sin_port);
printf("connection from %s, port %d\n", buff, cli_port);
for(;;) {
// Read from serial device into variable here, then send
if(send(connfd, "Data...Data...Data\n", 19, 0) < 0) {
printf("Client disconnected...\n");
break;
}
}
}
Looks like a duplicate of this, this and this.
Long story short you can't detect the disconnection until you perform some write (or read) on that connection. More exactly, even if it seems there is no error returned by send, this is not a guarantee that this operation was really sent and received by the client. The reason is that the socket operations are buffered and the payload of send is just queued so that the kernel will dispatch it later on.
Depending on the context, the requirements and the assumptions you can do something more.
For example, if you are under the hypothesys that you will send periodic message at constant frequency, you can use select and a timeout approach to detect an anomaly.
In other words if you have not received anything in the last 3 minutes you assume that there is an issue.
As you can easily found, this and this are a good read on the topic.
Look at that for a far more detailed explanation and other ideas.
What you call the ping (intended as a message that is sent for every received packet) is more similar to what is usually known as an ACK.
You only need something like that (ACK/NACK) if you also want to be sure that the client received and processed that message.
Thanks to #emmanuaf, this is the solution that fits my project criteria. The thing that I was missing was the MSG_NOSIGNAL flag, referenced here.
I use Mashpoe's C Vector Library to create a new vector, which will hold all of my incoming client connections.
int* client_array = vector_create();
I then spawn a pthread that continually reads from a serial device, stores that data in a variable, and then sends it to each client in the client list
void* serve_clients(int *vargp) {
for(;;) {
// Perform a microsleep
sleep(0.1);
// Read from the Serial device
// Get the size of the client array vector
int client_vector_size = vector_size(vargp);
for(int i = 0 ; i < client_vector_size ; i++) {
// Make a reference to the socket
int* conn_fd = &vargp[i];
/*
In order to properly handle client disconnects, we supply a MSG_NOSIGNAL
flag to the send() call. That way, if the client disconnects, we will
be able to detect this, and properly remove them from the client list.
Referenced from: https://beej.us/guide/bgnet/html//index.html#sendman
*/
if (send(*conn_fd, "Reply from server\n", 18, MSG_NOSIGNAL) < 0) {
printf("Client disconnected...\n");
// Close the client connection
close(*conn_fd);
// Remove client socket from the vector
vector_remove(vargp, i);
// Decrement index and client_server_size by 1
i--;
client_vector_size--;
}
}
}
}
To spawn the pthread:
// Spawn the thread that serves clients
pthread_t serving_thread;
pthread_create(&serving_thread, NULL, serve_clients, client_array);
When a new connection comes in, I simply add the new connection to the client vector
while(1) {
// Wait for incoming connection
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len);
if (-1 == connfd) {
perror("Could not accept incoming client");
continue;
}
//Resolving Client Address
char buff[INET_ADDRSTRLEN + 1] = {0};
inet_ntop(AF_INET, &cliaddr.sin_addr, buff, INET_ADDRSTRLEN);
uint16_t cli_port = ntohs(cliaddr.sin_port);
printf("connection from %s:%d -- Connfd: %d\n", buff, cli_port, connfd);
// Add client to vector list
vector_add(&client_array, connfd);
}
In the end, we have a TCP server that can multiplex data to many clients, and handle when those clients disconnect.
I am working on a project with C/C++ on Linux, and need to connect to two similar network devices using an API that I know just a little about.
The organization I have is 1 computer, and two ethernet adapters.
Let's call it lan1 adapter, is set to IP: 100.1.1.2 and the network device target is 100.1.1.1, with subnet 255.255.255.0.
lan2 adapter has IP: 100.1.2.2 and the network device target is 100.1.2.1, also with subnet 255.255.255.0
I am building two separate programs that each use the same net initialization code to connect to the network targets.
The problem is that after the first program initializes its connection to its respective network target, the other program fails to bind its port when it tries to initialize its own network connection to its respective target. I am not sure why this conflict between programs exists, seeing as how everything should be separate.
Below is the portion of the API that attempts to create a socket and bind a port:
static short create_socket(int port, UINT32 blocking)
{
int trycount =0;
struct sockaddr_in sin;
int r;
u_long yes = blocking ? 0 : 1; // nonblocking toggle
BOOL en = TRUE;
if ((our_socket= socket(PF_INET/*AF_INET*/, SOCK_DGRAM, 0)) <0)
{
printf("Socket open failed: %d\n", WSAGetLastError());
return -1;
}
if(!yes)
r = 0; // by default it is blocking
else
r= fcntl(our_socket,F_SETFL,O_NONBLOCK);
if(r<0)
{
printf("IOCTL failed setting blocking state: %d %d ", r, errno);
closesocket(our_socket);
return r;
}
bzero((char *) &sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons((unsigned short)port);
r = bind(our_socket, (struct sockaddr *) &sin, sizeof(sin));
while(r == EADDRINUSE && trycount <10 )
{
port ++;
sin.sin_port = htons((unsigned short)port);
r = bind(our_socket, (struct sockaddr *) &sin, sizeof(sin));
trycount ++;
}
if(r<0)
{
printf("Socket BIND failed: %d %d port %d\n", r, errno, port);
closesocket(our_socket);
return r;
}
r = setsockopt( our_socket, SOL_SOCKET, SO_BROADCAST, (const char *)&en, sizeof(en));
if(r)
{
printf("Socket Broadcast enable failed: %d\n", r);
closesocket(our_socket);
return r;
}
recvcount = 0;
return 0;
}
By default the blocking is enabled by the input argument, and the error throws the message "Socket BIND failed".
I have also tried disabling blocking, and instead get another error that socket file descriptor is marked as O_NONBLOCK and one of the operations (haven't figure out which yet) would cause it to block. Although, I'm not even sure the 'blocking' is the reason for the conflict between the two programs.
Any idea why the two separate programs conflict at this point in initializing the network connection to their respective targets, and how it might be avoided?
Thanks,
B
As per #EOF, the problem was
INADDR_ANY
in the line
sin.sin_addr.s_addr = INADDR_ANY;
which caused the port to be bound on all available network interfaces.
Edit: fixed a bad copy/paste problem
I would like to ask about the getpeername() function since it returns data as the title states. I tried to get value directly from accept() function, and the result also happens the same. Value of port seems to appear randomly even though value of address is correct(address is 127.0.0.1 since I run multi-processes on an only machine). The return code of getpeername() is 0 (status = 0). I'm using gcc version 4.8.1. I write a peer 2 peer chat application without server. The following is my code:
struct sockaddr_in addr;
socklen_t addr_len;
int tempPort, serverSockfd;
char test[100];
// Get serverSockfd successfully....
serverSockFd = initializeSock(PORT) // In this function I initialize socket(), bind() and listen(), serverSockFd is returned by the value of socket()
addr_len = sizeof addr;
newSock = accept(serverSockfd, (struct sockaddr *)&addr, &addr_len);
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
addr_len = sizeof addr;
if ((status = getpeername(newSock, (struct sockaddr *) &addr, &addr_len)) != 0){
printf("getpeername() error!\n");
}
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
Thanks very much for any your comment. Here is a partial code in initializeSock():
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("SocketInit(): socket() error!\n");
exit(1);
}
ret_val = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
if(ret_val == -1)
{
perror("SocketInit(): setsockopt(SO_REUSEADDR) error!\n");
exit(1);
}
gethostname(hostname,100);
host_entry = gethostbyname(hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
ret_val = bind(sd, (struct sockaddr*) &addr, sizeof(addr));
if(ret_val == -1)
{
perror("SocketInit(): bind() error!\n");
printf("For port:%d\n",port);
exit(1);
}
....
return sd;
This is the code to connect to server part of a peer. ConnectSock(portOfPeerA):
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("ConnectToServer(): socket() error!\n");
exit(1);
}
if (port != 0) {
addr.sin_family = AF_INET;
addr.sin_port = htons(portOfPeerA);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
// Do I need to bind() the port of peer B when it would like to connect to peer A?
ret_val = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
if(ret_val == -1)
{
printf("Error connect());
exit(1);
}
...
I don't know which port you accept from the peer, but if the peer is connecting to your server (e.g. then one calling accept) it will connect from a (more or less) random port, that's how TCP works. It connects from a fixed port only if the peer explicitly binds to that port before connecting.
This means, that the peers originating port is not defined on the server side (where your code fragments are from) but on the client side (the side which calls connect and where you only do connect but no bind).
But, please note that it might give problems with repeated connections, if both client and server use fixed IP and ports, because then you will get the same 4-tupel in TCP which defines the connections for repeated connections and thus go into all this trouble with the various TIME_WAIT states. So it is better to let the client just pick an available port and not force it to use a specific one.
getpeername() (and accept()) reports the IP and port that the remote party is locally bound to on its end. If the remote party is a client that did not call bind() before calling connect() then connect() performs an implicit bind to a random available port. That is what you are seeing, and that it typical usage. Most clients do not need to call bind() before connect(), but there are use cases where doing so is necessary, so don't rule it out.
This is the main code of my server program in C:
int main(int argc, char** argv)
{
int sock, connected, bytes_received, true = 1;
struct sockaddr_in server_addr, client_addr;
int sin_size;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket");
exit(1);
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof (int)) == -1) {
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[1]));
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero), 8);
if (bind(sock, (struct sockaddr *) &server_addr, sizeof (struct sockaddr))
== -1) {
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1) {
perror("Listen");
exit(1);
}
printf("\nTCPServer Waiting for client on port 5000");
fflush(stdout);
while (1)
{
pthread_t child;
sin_size = sizeof (struct sockaddr_in);
connected = accept(sock, (struct sockaddr *) &client_addr, &sin_size);
printf("\n I got a connection from (%s , %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
threadInfo info;
info.argumentsPassedToCode = argv;
info.connected = connected;
pthread_create(&child, NULL, interpretMessage, &info);
}
close(sock);
return 0;
}
My server always prints out the IP of the incoming connection, and the port that it is coming in from. I noticed that the ports are always increasing.
Is this normal? If not, what am I doing wrong?
If my server runs for a long time, will it run out of ports? If so, what will happen?
If your server is working, you're not doing anything wrong. Source ports aren't guaranteed to follow a pattern, they just exist to complete the connection tuple, (source port, source address, dest port, dest address).
Ports are reused once connections close, so you should be okay.
TCP has a state called TIME_WAIT which is used to make sure that everything have been sent and received properly before cleaning up the socket. This happens after you have closed the socket in you code. The time that a socket is in the TIME_WAIT state depends on the OS.
That's why you don't get the same port again for client connections.
You can read more about the state here: https://stackoverflow.com/questions/41602/how-to-forcibly-close-a-socket-in-time-wait
1) Yes; the next available port is selected. It can be the same port (if the prev socket was freed already by kernel), it can be the next free one or any other port which is free, from 1024 to 65535 (first 1024 are reserved as you know); In your case you are seeing a different client port number because either you are not properly closing the client socket or the previous socket is still lingering when you are making the next connection or you are just making multiple parallel connections
2) If you are not properly shutting down the sockets, you will (probably first run out of file descriptor if you have lower default per-process limits which is ... 1024 fds per proc?) ; If you do tear them down correctly then you'll be fine
all. I'm having a bit of weird problem with client server program. I have two different kinds of clients trying to connect to one server, one is just more barebone than the other with less things to do. But other wise they are practically the same. While the barebone code can connect to server and server accepts it fine, the elaborate version of it can't. The client says it's connected, sends messages (via both send() and sendto()) and gets number of bytes sent back. But the server doesn't recognize it. I'm not really sure why, esp upon comparing both versions of clients, they are really the same thing (at least until connect() is called), elaborate version has bind() whereas barebone version doesn't. Can anybody see a problem as to why these very similar codes don't work similar :P
if (argc == 3)
{
host = argv[1]; // server address
info.c_name = argv[2];
}
else
{
printf("plz read the manual, kthxbai\n");
exit(1);
}
hp = gethostbyname(host);
if (!hp)
exit(1);
printf("host found\n");
// setting up address and port structure information
bzero((char * ) &server_address, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(SERVER_PORT);
// opening up socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
exit(1);
else
printf("socket is opened: %i \n", sockfd);
info.sock_fd = sockfd;
// binding socket to a port: not in barebone version
rv = bind(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
if (rv < 0)
{
printf("MAIN: ERROR bind() %s\n", strerror(errno));
exit(1);
}
else
printf("socket is bound\n");
// connecting
rv = connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
printf("rv = %i\n", rv);
if (rv < 0)
{
printf("MAIN: ERROR connect() %i: %s\n", errno, strerror(errno));
exit(1);
}
else
printf("connected\n");
I'm not even sure where the problem is, whether it's the elaborate version of client or it's just the server? Thanks for any enlightenment.
If the code is really what you're using, your client is (magically!) connecting to itself, due to TCP's somewhat obscure Simultaneous connect support.
The problem here is that you aren't using the return for gethostbyname at all.
You also shouldn't bind the server port if it might be running on the local machine.