Sockets "hanging up" in C/buffer smaller than usual - c

When I send() and recv() data from my program locally it works fine.
However, on my remote server, the same program, which usually receives data in chunks of 4096, will receive in buffers capped at 1428, which rarely jump above this number.
Worse of all, after a minute or so of transferring data the socket just freezes and stops execution, and the program perpetually stays in this frozen state, like so:
Received: 4096
Received: 4096
Received: 3416
The server is simple, it accepts a connection from a client and receives data in chunks of 4096, which works absolutely fine locally, but on my remote server it is failing consistently, unless I only send a small chunk of data (sending 1000 byte files worked fine).
int main()
{
while(1){
int servSock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
if(servSock < 0){
fprintf(stderr, "Socket error.\n");
continue;
}
struct sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(atoi(STANDARD_PORT));
if(bind(servSock, (struct sockaddr*) &servAddr, sizeof(servAddr)) < 0){
fprintf(stderr, "Bind error.\n");
close(servSock);
continue;
}
if(listen(servSock, BACKLOG) < 0){
fprintf(stderr, "Listen error.\n");
close(servSock);
continue;
}
printf("%s", "Listening on socket for incoming connections.\n");
struct sockaddr_in clntAddr;
socklen_t clntAddrLen = sizeof(clntAddr);
while(1) {
int newsock = accept(servSock, (struct sockaddr*) &clntAddr, &clntAddrLen);
if(newsock < 0){
fprintf(stderr, "Accept connection error");
return 1;
continue;
}
char clntName[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &clntAddr.sin_addr.s_addr, clntName, sizeof(clntName)) != NULL)
printf("Handling client %s:%d\n", clntName, ntohs(clntAddr.sin_port));
char file[17];
memset(file, 0, 17);
int recvd = recv(newsock, file, 16, 0);
file[17] = '\0';
char local_file_path[200];
memset(local_file_path, 0, 200);
strcat(local_file_path, "/home/");
strcat(local_file_path, file);
printf(local_file_path);
FILE* fp = fopen(local_file_path, "wb");
char buffer[4096];
while(1)
{
memset(buffer, 0, 4096);
recvd = recv(newsock, buffer, 4096, 0);
printf("Received: %d\n", recvd);
fwrite(buffer, sizeof(char), recvd, fp);
if(recvd == -1 || recvd == 0) {
fclose(fp);
break;
} else
}
close(newsock);
}
close(servSock);
}
return 1;
}
EDIT: For more context, this is a Windows server I am adapting to linux. Perhaps the recv() call is blocking when it shouldn't be, I'm going to test with flags.

However, on my remote server, the same program, which usually receives data in chunks of 4096, will receive in buffers capped at 1428, which rarely jump above this number.
Insufficient context has been presented for confidence, but that looks like a plausible difference between a socket whose peer is on the same machine (one connected to localhost, for example) and one whose peer is physically separated from it by an ethernet network. The 1428 is pretty close to the typical MTU for such a network, and you have to allow space for protocol headers.
Additionally, you might be seeing that one system coallesces the payloads from multiple transport-layer packets more or differently than the other does, for any of a variety of reasons.
In any case, at the userspace level, the difference in transfer sizes for a stream socket is not semantically meaningful. In particular, you cannot rely upon one end of the connection to read data in the same size chunks that the other sends it. Nor can you necessarily rely on receiving data in full-buffer units, regardless of the total amount being transferred or the progress of the transfer.
Worse of all, after a minute or so of transferring data the socket just freezes and stops execution, and the program perpetually stays in this frozen state, like so:
"Worst" suggests other "bad", which you have not described. But yes, your code is susceptible to freezing. You will not see EOF on the socket until the remote peer closes their side, cleanly. The closure part is what EOF means for a network socket. The cleanness part is required, at the protocol level, for the local side to recognize the closure. If the other end holds the connection open but doesn't write anything else to it then just such a freeze will occur. If the other side is abruptly terminated, or physically or logically cut off from the network without a chance to close their socket, then just such a freeze will occur.
And indeed, you remarked in comments that ...
Both the client and the server are hanging. The client program just stops sending data, and the server freezes as well.
If the client hangs mid-transfer, then, following from the above, there is every reason to expect that the server will freeze, too. Thus, it sounds like you may be troubleshooting the wrong component.
Perhaps the recv() call is blocking when it shouldn't be, I'm going to test with flags.
There is every reason to think the recv() call is indeed blocking when you don't expect it to do. It's highly unlikely that it is blocking when it shouldn't.
It is possible to set timeouts for socket operations, so that they eventually will fail instead of hanging indefinitely when the remote side fails. Doing so would allow your server to recover, but it would not resolve the client-side issue. You'll need to look into that more deeply.*
*You might see the client unfreeze after the server times out and closes the connection on its end. Don't take that as a resolution.

Related

Using UDP transfer image

I have been working on how to transfer an image using UDP in C, I have created a code that sometimes works, sometimes it doesn't. In what I think the issue is that sometimes the server receives more packages than writes. I know that I am trying to create the TCP, but that is what I am kind looking for, but not sure how to do it.
I think to fix it the client should send the buff of the img and only sends the second part when the server reply back to the client.
Here is the code:
Client:
while (!feof(p))
{
fread(*&c, 1, BLEN, p);
sprintf(buf, "%s", *&c);
temp=sendto(s,buf,BLEN, 0, (struct sockaddr *) &si_other, slen);
//sleep(3);
//printf("%d ",temp);
if(temp < 0)
{
fprintf(stderr,"sendto error.\n");
printf("erro");
exit(1);
}
i++;
}
Server:
while(1){
if(recvfrom(s, buf, BLEN, 0, (struct sockaddr *) &si_other, (unsigned int *) &slen)==-1){
perror("recvfrom error.\n");
exit(1);
}
//printf("%s ", &si_other);
flagr[0] = buf[0];
flagr[1] = buf[1];
flagr[2] = buf[2];
if (strcmp(flagr, flag) == 0 ){
break;
}
fwrite(buf, 1, BLEN, pp);
i++;
}
UDP is a datagram protocol, meaning that each call to sendto sends one message. If that message is larger than an IP packet can hold, it will be fragmented across multiple IP datagrams. If any one of those fragments fails to arrive, the whole thing is dropped at the OS level.
The data needs to be sent in chunks of no more than about 1450 bytes. Then the receiving side will need to read each packet and, because UDP does not guarantee that data will arrive in order, you will need to reassemble them in the proper order.
That means each packet has to have a user-defined header which contains the sequence number so that the receiver knows what order to put them in.
You also need to worry about retransmissions, since UDP doesn't guarantee that a packet that is send is actually received.
There's a program I wrote called UFTP which does all of this. Take a look at the documentation and code to get an idea of what you need to do to implement reliable data transfer over UDP.

Why am I getting a segmentation fault in my C server program (but only sometimes)?

Right now, I'm trying to write a simple client/server application in order to measure the round trip time on a LAN for TCP messages of various sizes (I'm doing the timing client side). The program works fine for small packet sizes (> 1000 bytes) but I end up with a segmentation fault: 11 error for inputs of larger magnitude (10KB or greater).
int main()
{
struct sockaddr_in sin;
char buf[MAX_LINE];
int len;
int s, new_s;
/* build address data structure */
bzero((char *)& sin, sizeof( sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons( SERVER_PORT);
/* setup passive open */
if (( s = socket( PF_INET, SOCK_STREAM, 0)) < 0) {
perror("tcp program: socket");
exit(1);
}
if (( bind(s, (struct sockaddr *)& sin, sizeof(sin))) < 0) {
perror("tcp program: bind");
exit( 1);
}
listen(s, MAX_PENDING);
/* wait for connection, then receive and print text */
while(1) {
socklen_t lent = (unsigned int)&len;
if ((new_s = accept(s, (struct sockaddr *)& sin, &lent)) < 0) {
perror("tcp program: accept");
exit( 1);
}
while ((len = recv(new_s, buf, sizeof(buf), 0))){
char msg[len];
send( new_s, msg, len, 0); //echo message of same length as received message
}
close(new_s);
}
}
Again, the goal was to measure RTT, so I wanted the client to send a message, the above server to receive it, then send back a message of equivalent size. I also wanted the server to continue spinning so that the client could run iteratively, sending messages of 1KB, 10KB,...1000KB, etc. However, such iterations usually result in a segmentation fault.
Oddly enough, if I configure my client to run, for example, a single 12KB message send, the server does fine, and continues to run. And if I wait a couple of seconds, I can even repeatedly call my client and the server keeps up. But if I run the single message send in rapid succession, I end up with the segfault again.
Any ideas? I apologize in advance for any elementary errors in style or format. This is my first real foray into the C language beyond "hello world".
Thanks!
I don't know if this is the only part of the code that is wrong, but this is wrong:
while ((len = recv(new_s, buf, sizeof(buf), 0)))
Please read the man page for recv(), in particular (emphasis added)...
These calls return the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer has performed an orderly shutdown.
We know that networks are unreliable, and it is fairly common for recv() and friends to return errors.
Additionally, variable-length arrays in C are a fairly dangerous construct, because they perform dynamic allocation on the stack. They're basically alloca() in disguise, and we know how dangerous alloca() is. So this bit:
char msg[len]; // serious problems unless we have good bounds for len

How do you keep a socket connection open indefinitely in C?

I'm trying to implement a C socket server in Linux using the code from Beej's sockets guide, which is here:
http://beej.us/guide/bgnet/examples/server.c
This works, and I've written a Windows client in C# to communicate with it. Once the client connects, I have it send a byte array to the server, the server reads it, then sends back a byte array. This works.
However, after this, if I have the client try to send another byte array, I get a Windows popup saying "An established connection was aborted by the software in your host machine." Then I have to re-connect with the client again. I want to keep the connection open indefinitely, until the client sends a disconnect command, but despite reading through Beej's guide, I just don't seem to get it. I'm not even trying to implement the disconnect command at present, I'm just trying to keep the connection open until I close the server.
I've tried removing the close() calls in Beej's code:
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
ProcessRequest(new_fd); // this is not Beej's code, I've replaced his code here (which was a simple string send()) with a function call that does a read() call, processes some data, then sends back a byte array to the client using send().
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
But that just gets me an infinite loop of "socket accept: bad file descriptor" (I tried removing both the close(new_fd) lines, together and apart, and the close(sockfd) as well.
Can anyone more versed with C socket programming give me a hint where I should be looking? Thank you.
The reason for the accept() problem is that sockfd isn't valid. You must have closed it somewhere. NB if you get such an error you shouldn't just keep retrying as though it hadn't happened.
The reason for the client problem is that you're only processing one request in ProcessRequest(), as its name suggests, and as you describe in your comment. Use a loop, reading requests until recv() returns zero or an error occurs.
Cause
The reason client faces error is because of close(new_fd) either by the server-parent or server-child.
Solution
At any point of time, a server may get two kind of events:
Connection request from a new client
Data from an existing client
The server have to honor both of them. There are two (major) ways to handle this.
Solution Approach 1
Design the server as a concurrent server. In Beej's guide it is
7.2. select()—Synchronous I/O Multiplexing
http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#select
Since OP's approach is not this one, we do not explore it further.
Solution Approach 2
At server, fork() a process per client. This is the approach OP has taken and we explore here. Essentially, it is fine tuning the ProcessRequest() function in OP's code. Here is a sketch.
void ProcessRequest( int new_fd ) {
char buffer[ N ];
for( ; ; ) { // infinite loop until client disconnects or some error
int const recvLen = recv( new_fd, buffer, sizeof buffer, 0 );
if( recvLen == 0 ) { break; } // client disconnected
else if( recvLen == -1 ) { perror( "recv" ); break; }
int const sendLen = send( new_fd, buffer, recvLen, 0 );
if( sendLen == -1 ) { perror( "send" ); break; }
// TODO if( sendLen < recvLen ) then send() in loop
}
}
Note
I am sorry for having the half-baked solution four few hours. While I was editing the answer, I lost connectivity to stackoverflow.com which lasted for couple of hours.

Transferring files using UDP sockets in C

I'm fairly new to socket programming in C, so the code below may have a ton of newbie mistakes.
I'm trying to make a client-server application in which the server will transfer a file to the client using an UDP socket. Both the client and the server will run on Linux hosts. It's an assignment, so it has to be done that way. Other client-server communications may use a TCP socket, but the file transfer MUST be via UDP. The program works correctly for small files, but if I try to send a slightly larger file (say, a 600 kb text file), the client will stop receiving the packets, even though the server will send them all. Here's the file transfer part of the server code:
FILE* myFile;
long fileSize, readBytes, sentBytes, sizeCheck;
uint32_t encodedFileSize;
myFile = fopen(fileName, "rb");
if(myFile == NULL)
{
perror("Error when opening file.");
exit(1);
}
fseek(myFile, 0, SEEK_END);
fileSize = ftell(myFile);
encodedFileSize = htonl(fileSize);
rewind(myFile);
sizeCheck = 0;
write(myTCPSocket, &encodedFileSize, sizeof(encodedFileSize));
if(fileSize > 255)
{
while(sizeCheck < fileSize)
{
readBytes = fread(bufferRW, 1, 256, myFile);
sentBytes = sendto(sockfdUDP, bufferRW, readBytes, 0, (struct sockaddr*)&cli_addr, udpAddressSize);
sizeCheck += sentBytes;
}
}
else
{
readBytes = fread(bufferRW, 1, 256, myFile);
sentBytes = sendto(sockfdUDP, bufferRW, readBytes, 0, (struct sockaddr*)&cli_addr, udpAddressSize);
}
if(fileSize == sizeCheck)
{
printf("Success.\n");
}
else
{
printf("Fail.\n");
}
fclose(myFile);
fflush(stdout);
close(sockfdUDP);
As you can see, I used a TCP socket to send the client the file size. Here's the client code:
FILE *myFile;
long receivedBytes, writtenBytes, sizeCheck;
long fileSize, realFileSize;
char ack2[5] = "Ok";
sockfdUDP = socket(AF_INET, SOCK_DGRAM, 0);
read(socketTCP, &fileSize, sizeof(long));
realFileSize = ntohl(fileSize);
myFile = fopen(fileName, "wb");
if(myFile == NULL)
{
perror("Error when creating file.");
exit(1);
}
sizeCheck = 0;
if((realFileSize) > 255)
{
while(sizeCheck < (realFileSize))
{
receivedBytes = recvfrom(sockfdUDP, bufferRW, 256, 0, (struct sockaddr*)&serv_addr, &serv_addr_size);
writtenBytes = fwrite(bufferRW, 1, receivedBytes, myFile);
fflush(myFile);
sizeCheck += writtenBytes;
}
}
else
{
receivedBytes = recvfrom(sockfdUDP, bufferRW, 256, 0, (struct sockaddr*)&serv_addr, &serv_addr_size);
fwrite(bufferRW, 1, receivedBytes, myFile);
fflush(myFile);
}
if(realFileSize == sizeCheck)
{
printf("Success.");
}
else
{
printf("Fail.");
}
fclose(myFile);
close(sockfdUDP);
The "bufferRW" buffer was originally declared as char bufferRW[256] and passed to the function as an argument. Same goes for other undeclared variables.
Like I said before, the server will (apparently) send the whole file without any issues. However, the client will stop receiving packets after it's written about 423936 bytes (this may vary between executions). It'll just stay at the recvfrom line, without reading anything.
Now, I'm sure the problem is not being caused by a faulty connection since I'm testing both processes on the same host. And before you ask "What is it with the 256 byte packet size?", there's this weird bug that will throw me a segmentation fault on the realFileSize = ntohl(fileSize); client line if I use a buffer size of, say, 1500.
Could you please tell me what am I missing here?
EDIT: I'm trying with different file sizes now. It seems to handle files larger than 256 bytes without issue (it enters and exits the while loops correctly on both client and server), but the client will start having problems when the file is bigger than, say, 300 kb.
EDIT 2: I just debugged the program. Apparently, the server sends the entire file before the client can even enter its while loop.
EDIT 3: I think I know what's causing the issue. It seems like if the server sends a bunch of packets before the client starts reading, the client will read up to 278 packets, regardless of their size. If I try sending, say, 279 before the client starts reading it won't read the 279th packet. So if the server sends its packets fast enough, the number of packets that the client hasn't read yet will exceed 278 and the client won't finish reading all of the packets. Any ideas on how to fix this?
long* fileSize declared a pointer to a long, but in your code, it's pointing nowhere. In fact, it's pointing to a random address. You should declare it as long fileSize, and call read(socketTCP, &fileSize, sizeof(long)) instead.
You should check the return value of read, write, etc, to guarantee they did not fail. For example, sendto returns -1 on error. You're ignoring this, and incrementing sizeCheck with this value anyway.
UDP is not a reliable protocol for file transfers, but if you cannot do without it, you better implement some controls that TCP already gives you for free, like packet reordering, data checksum, etc. And that can be a very complex task by itself.
Compile your code with -Wall -Wextra. The compiler will give you hints about what could be potentially wrong. I see you're still using *fileSize in a comparison, which is clearly wrong.
After you fix the *fileSize issue, your loop-condition is still using the wrong value (due to fileSize = ntohl(fileSize)). You need to store this value in another variable, or change your loop-condition to use the real file size.
Regarding your EDIT 3, you need to somehow synchronise your client & server, so they can start the transmission at the same time. However, a sender that is much faster than the receiver will still cause packet loss. To solve this, you'll also need to implement packet acknowledgement, and retransmit a packet if the sender doesn't receive an ACK for a respective sent packet after a timeout. This is something TCP already does for you.
A simpler (but not completely reliable) way, would be to slow down the sending process a bit - maybe using nanosleep between each call to sendto.

What could be the cause of very slow socket reads?

I am using blocking TCP sockets for my client and server. Whenever I read, I first check whether data is available on the stream using select. I always read and write 40 bytes at a time. While most reads take few milliseconds or less, some just take more than half a second. That after I know that there is data available on the socket.
I am also using TCP_NODELAY
What could be causing it ?
EDIT 2
I analyzed the timestamp for each packet sent and received and saw that this delay happens only when client tries to read the object before the next object is written by the server. For instance, the server wrote object number x and after that the client tried to read object x, before the server was able to begin writing object number x+1. This makes me suspect that some kind of coalescing is taking place on the server side.
EDIT
The server is listening on 3 different ports. The client connects one by one to each of these ports.
There are three connections : One that sends some data frequently from the server to the client. A second one that only sends data from the client to the server. And a third one that is used very rarely to send single byte of data. I am facing the problem with the first connection. I am checking using select() that data is available on that connection and then when I timestamp the 40 byte read, I find that about half a second was taken for that read.
Any pointers as to how to profile this would be very helpful
using gcc on linux.
rdrr_server_start(void)
{
int rr_sd;
int input_sd;
int ack_sd;
int fp_sd;
startTcpServer(&rr_sd, remote_rr_port);
startTcpServer(&input_sd, remote_input_port);
startTcpServer(&ack_sd, remote_ack_port);
startTcpServer(&fp_sd, remote_fp_port);
connFD_rr = getTcpConnection(rr_sd);
connFD_input = getTcpConnection(input_sd);
connFD_ack= getTcpConnection(ack_sd);
connFD_fp=getTcpConnection(fp_sd);
}
static int getTcpConnection(int sd)
{
socklen_t l en;
struct sockaddr_in clientAddress;
len = sizeof(clientAddress);
int connFD = accept(sd, (struct sockaddr*) &clientAddress, &len);
nodelay(connFD);
fflush(stdout);
return connFD;
}
static void
startTcpServer(int *sd, const int port)
{
*sd= socket(AF_INET, SOCK_STREAM, 0);
ASSERT(*sd>0);
// Set socket option so that port can be reused
int enable = 1;
setsockopt(*sd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
struct sockaddr_in a;
memset(&a,0,sizeof(a));
a.sin_family = AF_INET;
a.sin_port = port;
a.sin_addr.s_addr = INADDR_ANY;
int bindResult = bind(*sd, (struct sockaddr *) &a, sizeof(a));
ASSERT(bindResult ==0);
listen(*sd,2);
}
static void nodelay(int fd) {
int flag=1;
ASSERT(setsockopt(fd, SOL_TCP, TCP_NODELAY, &flag, sizeof flag)==0);
}
startTcpClient() {
connFD_rr = socket(AF_INET, SOCK_STREAM, 0);
connFD_input = socket(AF_INET, SOCK_STREAM, 0);
connFD_ack = socket(AF_INET, SOCK_STREAM, 0);
connFD_fp= socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in a;
memset(&a,0,sizeof(a));
a.sin_family = AF_INET;
a.sin_port = remote_rr_port;
a.sin_addr.s_addr = inet_addr(remote_server_ip);
int CONNECT_TO_SERVER= connect(connFD_rr, &a, sizeof(a));
ASSERT(CONNECT_TO_SERVER==0) ;
a.sin_port = remote_input_port;
CONNECT_TO_SERVER= connect(connFD_input, &a, sizeof(a));
ASSERT(CONNECT_TO_SERVER==0) ;
a.sin_port = remote_ack_port;
CONNECT_TO_SERVER= connect(connFD_ack, &a, sizeof(a));
ASSERT(CONNECT_TO_SERVER==0) ;
a.sin_port = remote_fp_port;
CONNECT_TO_SERVER= connect(connFD_fp, &a, sizeof(a));
ASSERT(CONNECT_TO_SERVER==0) ;
nodelay(connFD_rr);
nodelay(connFD_input);
nodelay(connFD_ack);
nodelay(connFD_fp);
}
I would be suspicious of the this line of code:
ASSERT(setsockopt(fd, SOL_TCP, TCP_NODELAY, &flag, sizeof flag)==0);
If you are running a release build, then ASSERT is mostly likely defined to nothing, so the call would not actually be made. The setsockopt call should not be in the ASSERT statement. Instead, the return value (in a variable) should be verified in the assert statement. Asserts with side effects are generally a bad thing. So even if this is not the problem, it should probably be changed.
One client and multiple connections?
some of socket functions might be blocking your execution (i.e. waiting for result of functions). I would suggest opening a new thread (on server side) for each connection so they won't interfere with each other...
but I'm shooting in the dark; you'll need to send some additional info...
Your statement is still confusing i.e. "multiple tcp connections with only one client". Obviously you have a single server listening on one port. Now if you have multiple connections this means there is more than one client connecting to the server each connected on a different tcp client port. Now server runs select and responds to whichever client has data (meaning client sent some data on his socket). Now if two clients send data simultaneously, server can only process them sequentially. So second client won't get processed until server is done processing with first.
Select only allows server to monitor more than one descriptors (sockets) and process which ever has data available. It is not like that it does processing in parallel. You need multiple threads or processes for that.
Maybe it is something related to the timeout argument.
What do you set for timeout argument of select call?
Try to change the timeout argument to a bigger one and observe the latency. Sometimes too small timeout and very often system calls can actually kill throughput . Maybe you can achieve better results if you assume a little bigger latency, that is realizable.
I suspect timeout or some code bug.
You may try using TCP_CORK (CORK'ed mode) with kernel extensions GRO, GSO and TSO disabled by ethtool:
sending inside TCP_CORK flagged session will ensure that the data will not be sent in partial segment
disabling generic-segmentation-offload, generic-receive-offload and tcp-segmentation-offload will ensure that kernel will not introduce artificial delays to collect additional tcp segments before moving data to/from userspace

Resources