A J Brockberg
A J Brockberg

Reputation: 613

read complete data on tcp socket in local network

I have a server application and a client application both written in c. Both communicate on a tcp socket. I want to send a chunk of data from client to server and also from server to client.

I have tested this for maximum 2262 bytes.

I found when I send 2262 bytes from server (running debian 7) to client (running ubuntu 14.04 LTS) I am able to receive all the bytes at once (both are in a local network communicating over wlan).

But when I try to send same number of bytes from client to server I am only able to read 1448 number of bytes (oftenly) and 3000 bytes few times (3000 bytes is the maximum number of bytes I want to read from file descriptor) at once on server.

I also found if I run both the server and client application on the same machine I am able to send and receive 2262 bytes from server to client and also from client to server at once. I tested all the cases for many times before putting this question here.

I also referred the Beejs Guide for this where I found first I must ensure that I am sending the exact number of bytes at once. I checked this with the both send and write functions and I found I am sending all the bytes at once only.

I also found in that book the same question with MTU topic.

My first question is if Maximum transmission unit is the reason then why am I able to send same amount of data from server to client and not able to receive from client to server?

My second question is if it is not possible to send or receive chunks of data (definitely less than 10 Kbytes) at once from both the server and client, Beej has suggested a way of son of data encapsulation for this. Is there any other way than this method suggested by Beej to send and receive data ( upto 10 Kbytes or might be more than that also) at once?

Client code is just continuously writing 2262 bytes on server socket. Here is the server code.

 #include<stdio.h>
 #include<string.h>    //strlen
 #include<stdlib.h>    //strlen
 #include<sys/socket.h>
 #include<arpa/inet.h> //inet_addr
 #include<unistd.h>    //write
 #include<pthread.h> //for threading , link with lpthread

 #define MAX_SIZE 3000 

//the thread function
void *connection_handler(void *);

int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , *new_sock;
struct sockaddr_in server , client;

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
    printf("Could not create socket");
}
puts("Socket created");

//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 6000 );

//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
    //print the error message
    perror("bind failed. Error");
    return 1;
}
puts("bind done");

//Listen
listen(socket_desc , 3);

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);

while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
{
    puts("Connection accepted");

    pthread_t sniffer_thread;
    new_sock = malloc(1);
    *new_sock = client_sock;

    if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
    {
        perror("could not create thread");
        return 1;
    }

    //Now join the thread , so that we dont terminate before the thread
    //pthread_join( sniffer_thread , NULL);
    puts("Handler assigned");
}

if (client_sock < 0)
{
    perror("accept failed");
    return 1;
}

return 0;
}

/*
 * This will handle connection for each client
* */
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size, i;
uint8_t message[MAX_SIZE];

//Receive a message from client
while( (read_size = read(sock , message , sizeof(message))) > 0 )
{
i = 0;
printf("bytes read- %d\n", read_size);

}

if(read_size == 0)
{
    puts("Client disconnected");
    fflush(stdout);
}
else if(read_size == -1)
{
    perror("recv failed");
}

//Free the socket pointer
free(socket_desc);

return 0;
}

Upvotes: 1

Views: 1506

Answers (2)

SergeyA
SergeyA

Reputation: 62583

Forget all about MTU. The very reason for TCP existence is to protect you (the user) from low-level UDP stuff, including MTU. TCP is a stream-oriented protocol. You pour bytes on one side, you read bytes on the other. Sizes do not matter. No matter how much you've poured on one side, you never how much you can pick up on the receiver side at any given time. The only sane way of using TCP is by reading a stream without expecting any specific number of bytes delivered through each recv() call and dealing with whatever you got.

Upvotes: 0

Sel&#231;uk Cihan
Sel&#231;uk Cihan

Reputation: 2034

Quoting from http://linux.die.net/man/2/read

Return Value

On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal

So read does not work as you expect it to work. It does not guarantee that it will return the amount you requested, in one call. The amount you specify is only an upper bound on the actual data you recieve.

Upvotes: 1

Related Questions