6/20/08

Simple sender/receiver program to calculate the Round Trip Time

Here are two simple programs, the one named sender and the other named receiver.
Sender is the one who want to calculate the mean Round Trip Delay for the connection between sender and receiver.
So sender sends a hundred (100) packets, sized 1byte each (a char in C programming Language), and wait to get it back from the receiver.
Now it's clear that the receiver just receives packets and send them back without any delay.
Code is after the output.

When running you will get this output from the receiver:

Connection to sender established
Receive 100 packets of 1 byte and send then back
Done
Close socket and exit

and from the server:

Sending 100 messages 1 byte each and wait for ack.
RTT = 2.65503e-05 ms
close sockets and exit


Here is the code for the receiver which is less complicated than the sender's

#include <string.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>

#define SENDER_PORT 3490
#define SENDER_IP "127.0.0.1"

int main(int argc, char *argv[]) {

int sockfd;
int rcv_num,loop_count,i;
char buf;
struct sockaddr_in sender_addr;

//open socket and connect
if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) ==-1){
perror("socket error"); // do some error checking!
exit(1);
}

sender_addr.sin_family = AF_INET;
sender_addr.sin_port = htons(SENDER_PORT);
sender_addr.sin_addr.s_addr = inet_addr(SENDER_IP);
memset(sender_addr.sin_zero, '\0', sizeof(sender_addr.sin_zero));

if ((connect(sockfd,(struct sockaddr *)&sender_addr,sizeof(sender_addr))) ==-1){
perror("connect error"); // do some error checking!
exit(1);
}

//connection established
printf("Connection to sender established\n");
//reads 100 packets of 1 byte and sends them back as ack packets
printf("Receive 100 packets of 1 byte and send then back\n");
for(i=0;i<100;i++){
rcv_num = recv(sockfd,&buf,sizeof(char),0);
if(rcv_num!=0) {
//send ack
send(sockfd,&buf,sizeof(char),0);
}
else{
perror("Receive error");
exit(1);
}
}
printf("\tDone\nClose socket and exit\n");
close(sockfd);
exit(0);
}

As you will understand if you look the code above receiver considers sender to be at ip 127.0.0.1. This is the local host. This means that these two programs (sender and receiver) runs locally. This doesn't matter. If you change the SENDER_PORT and the SENDER_IP to the real ones and you run them at two different computers in the world you will have the same output (with different RTT of course)
Well, now it's time for the senders code. I will explain both better in a while.

#include <string.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>

#define MYPORT 3490
#define SIZE_TO_SEND 1000
#define MY_IP "127.0.0.1"

int main(int argc, char *argv[]) {
int sockfd,sockfd2;
char tosend = 's'; //a char (1byte) to send to receivers
char ack;
struct sockaddr_in my_addr,rcvr_addr;
struct timeval start,end;
int sin_size = sizeof(my_addr),i,k,num_packet_sent,optval;
double t1,t2;

//open TCP socket,bind and accept RECEIVERS connections
if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) ==-1){
perror("socket error");
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);
my_addr.sin_addr.s_addr = inet_addr(MY_IP);
memset(my_addr.sin_zero, '\0', sizeof(my_addr.sin_zero));
//allow reuse of port
optval = 1;
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//bind(socketfd, struct about my address,sizeofmy address);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) == -1) {
perror("bind");
exit(1);
}
listen(sockfd,10);

sockfd2 = accept(sockfd, (struct sockaddr *)&rcvr_addr, &sin_size);

//connections OK
//send 100 packet of size 1 byte and for each send wait for ack
t1=0.0; t2=0.0;
printf("Sending 100 messages 1 byte each and wait for ack.\n");
for(num_packet_sent=0;num_packet_sent<100;num_packet_sent++){
if(gettimeofday(&start,NULL)) {
printf("time failed\n");
exit(1);
}
send(sockfd2,&tosend,sizeof(char),0);
optval=recv(sockfd2,&ack,sizeof(char),0);
if(optval==-1) {
perror("Receive error");
exit(1);
}
else{
if(gettimeofday(&end,NULL)) {
printf("time failed\n");
exit(1);
}
t1+=start.tv_sec+(start.tv_usec/1000000.0);
t2+=end.tv_sec+(end.tv_usec/1000000.0);
}
}
//calculate and print mean rtt
printf("RTT = %g ms\n",(t2-t1)/100);
printf("close sockets and exit\n");
shutdown(sockfd2,2);
shutdown(sockfd,2);
exit(0);
}

Now let's explain these lines.
Both sender and receiver uses the command socket() to open a socket for the communication. Receiver uses connect() with arguments a struct sockaddr_in to connect to the sender. Sender uses bind() to give the sockfd the local address so that it can then call accept and connect to the receiver. After bind() the sender calls accept() which block until somebody connects (call connect()) to the socket.
When connection is established sender send 100 packets , every one is 1byte (char tosend) and receives another one back. Double t1 sume the start times (before send()) and double t2 sums the end times(after recv()). When all 100 packets are sent RTT is calculated by (t2-t1)/100
This is better than calculate rtt for every packet and then sum them and divide by 100.

Sum ( t2i-t1i ) / 100 equals ( sum(t2i)-sum(t1i) ) / 100 for 0 <= i < 100

I don't think I have to say more. If you want to ask something just post it and I will come back to you or send me a mail.
Thank you.

12 comments:

Anonymous said...

Hi. I am trying to write a C code to calculate jitter, delay, RTT etc. your code is of great help indeed. Can you tell if we can calculate the delay of a tcp packet using C socket programming?? and some hints on how to calculate jitter.. I wud b greatful.. thanks in advance

KANDIMALLA's said...

Hi,
I want to send text data , audio data and video data and calculate RTT for each through different ports.can u give any idea regarding that.



Thanks in advance

Andreas Papadopoulos said...

Hello,
First of all I 'd like to thank you for visiting my blog.

The code is the same and it doesn't matter what you want to transfer.
In the example I only send 100 packets of 1 byte (char).
If you read the manual for send and receive you can give as second parameter a pointer to anything (void *).

That means you need to read into a buffer what you want to send and then pass it as argument.
In addition you will probably need to inform receiver (by sending an int) for the number of bytes you will send.

I hope this helped.
I am waiting for your response.

prem said...

hi i want to calculate rtt and its average,max,min in my ping program can u just help me how to calculate it

Andreas Papadopoulos said...

Hello,

Most of the code is the same.
You just need to modify the sender code and specifically lines 63 to 64.

Please see my previous post about How to calculate elapsed time in C/C++
You need to measure time for sending a char and receiving ack. Maybe store the 100 (or N) values you get in an array and process them after exiting the for (started at sender line 47).

I hope this helps you.
Good luck and thank you for visiting Another Computers Blog.
Any comments are welcomed.

Anonymous said...

is this program compiled by gcc or g++ compiler?

Andreas Papadopoulos said...

Hello my friend,

It was compiled with gcc but I think it can be compiled with icc as well.

Thank you

Unknown said...

how to run them. please explain the steps.

Andreas Papadopoulos said...

Hello there,

You have to compile separately the two C source files.
Then open two terminal windows and execute at terminal 1 the receiver and at terminal 2 the sender.
That's it!
Hope it helps you

Anonymous said...

Thankyou for the code sir but the header file arpa/inet is not working at my end..any idea what cold be wrong.

Unknown said...

Hi,

I am using a sencer/receiver program to calculate the Round Trip Time with RTnet.
See the following code. The problem is the compiler does not find my "task.h" header file so I just copied it to the same directory as my Makefile. Now there appear several errors: undefined reference to rt_task_self, undefined reference to rt_task_inquire and so on. All these functions are in my "task.h" header file. How do I define them?

Sender program:
#include
#include
#include
#include
#include
#include
#include

/*XENOMAI*/
#include
#include
#include

#define SERVER "192.168.127.9"
#define BUFLEN 512
#define PORT 8888

void die(char *s)
{
perror(s);
exit(1);
}

... cannot post much more here

Andreas Papadopoulos said...

Hi,
You do not need to include "task.h" header file.