UDP throughput tool: unusually low throughput

UDP throughput tool: unusually low throughput

Post by vishnu raja » Fri, 14 Feb 2003 09:17:04



Hi all,

I need a software to take UDP throughput measurements over a wireless LAN
(802.11b). I've written a piece of code (sender and receiver) that however,
give me a throughput of only around 3Mbps whereas I expect a throughput of
9-10Mbps.

   When I run the code between a laptop wireless linked to an Access Point
that has a desktop machine connected to it (by crossconnect cable), I get
100% packets received ie there is no packet loss, however I get a low
throughput. However, when I run both the sender and the receiver on the same
machine (loopback), I get a throughput of 400 Mbps. All systems run Red Hat
linux.

Here's what my code does: the sender (client) sends UDP packets of a
specified size (i generallyl give 1500 bytes becfause that's the largest
MTU) and specified number (depending on the file size) to the receiver
(server) which then sends it back to the sender.

The sender calculates the time taken for each packet (roundtrip) by
accessing the timestamps on the packets and adds this on to a variable which
keeps getting incremented with the overall time of all the packets. This
information along with the information about the number of bytes received is
used to calculate the throughput.

usage:

receiver:
newreceiver2 <sender_ip>
eg: newreceiver2 136.142.117.75

sender:
newsender4 <recv_ip_address> <packet_size> <file_size>
eg:
newsender4 136.142.117.6 1500 1500000

the above example will fire one thousand 1500 byte packets between the
sender and the receiver and back.

Here's the code. Any ideas on what is wrong?

//receiver

#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>

#define MAXSIZE 1500

main(int argc, char *argv[])
{
int i,sock,len,retval;
int pkt_size;
long int cnt=0;

char buf[100];
struct sockaddr_in self,peer;
struct hostent *hp,*sp;
struct timeval tstart,tend,tv;
fd_set rfds,tfds;

typedef struct initval
{
int pkt_size;
int no_of_pkts;

Quote:}header;

typedef struct pkt_data
{
unsigned long pkt_no;
struct timeval t1,t2,t3,tv;
char data[MAXSIZE];

Quote:}packet;

header h1;
packet p,p1;

if(argc<2)
{
printf(" USAGE: receiver <sender_ip_addr>\n");
exit(1);

Quote:}

if (( sock=socket(PF_INET,SOCK_DGRAM,0))==-1)
{
printf(" Unable to create socket \n");
exit(1);

Quote:}

self.sin_family=AF_INET;
self.sin_port=htons(2502);
gethostname(buf,sizeof(buf));

if((hp=gethostbyname(buf))<=0)
{
printf(" Error: gethostname \n");
exit(1);

Quote:}

bcopy(hp->h_addr,&self.sin_addr,hp->h_length);
len=sizeof(struct sockaddr_in);

if((bind(sock,(struct sockaddr *)&self,len))==-1)
{
printf("Error: bind\n");
exit(1);

Quote:}

peer.sin_family=AF_INET;
peer.sin_port=htons(2510);
if ((sp=gethostbyname(argv[1]))<=0)
{
printf(" Error: gethostbyname\n");
exit(1);
Quote:}

bcopy(sp->h_addr,&peer.sin_addr,sp->h_length);

printf(" Receiver ready for packets\n");

// now getting packet and file info
/*
while(1)
{
FD_ZERO(&rfds);
FD_SET(sock,&rfds);
tv.tv_sec=100;
tv.tv_usec=0;
retval=select(sock+1,&rfds,NULL,NULL,&tv);
if (!retval) break;
*/
if(recvfrom(sock,&h1,sizeof(struct initval),0,(struct sockaddr
*)&peer,&len)<0)
{
printf(" error: recv1\n");

Quote:}

printf("The packet size is %d \n",h1.pkt_size);
printf("The number of packets are %d\n",h1.no_of_pkts);
pkt_size=h1.pkt_size;

while(1)
{
if(recvfrom(sock,&p,sizeof(char)*(pkt_size),0,(struct sockaddr
*)&peer,&len)>0)
{
cnt++;

if((sendto(sock,&p,sizeof(char)*(pkt_size),0,(struct sockaddr
*)&peer,len))>0)
{

Quote:}
}
}

printf(" Total packets received: %ld\n",cnt);

Quote:}

*************************************************************

//sender

#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <netdb.h>

#define MAXSIZE 1500

main(int argc,char *argv[])
{
FILE *fp;
int i=0,len=0,sock,pkt_size,datasize,n,k=0;
long int cnt=0;
long lapse=0;
long pkts_received=0;
long timetaken;
char buf[100];
struct sockaddr_in self,their;
struct hostent *hp,*sp;
struct timeval tstart,tend;

typedef struct pkt_data
{
unsigned short pkt_no;
struct timeval t1,t2,t3;
char data[MAXSIZE];

Quote:} packet;

typedef struct initval
{
int pkt_size;
int no_of_pkts;

Quote:}header;

header h1;
packet *p,p1;

//error checking for command line arguments
if(argc<4)
{
printf("USAGE: sender <receiver_ip_addr> <packet-size> <file_size>\n");
exit(1);

Quote:}

pkt_size=atoi(argv[2]);
datasize=pkt_size-26;
h1.pkt_size=pkt_size;
p=malloc(sizeof(struct pkt_data));

//initializing the data field of the packet to zeros
for(i=0;i<datasize-1;p->data[i++]='0');
p->data[i]='\0';

//calculating the number of packets for a given packet size and file size
n=atoi(argv[3])/atoi(argv[2]);

h1.no_of_pkts=n;

//creating a datagram socket
if((sock=socket(PF_INET,SOCK_DGRAM,0))==-1)
{
printf("Unable to create socket \n");
exit(1);

Quote:}

self.sin_family=AF_INET;
self.sin_port=htons(2510);
printf("sender port: 2510\n");

if(gethostname(buf,sizeof(buf))==-1)
{
printf("Get Host Name failed \n");
exit(1);

Quote:}

if((hp=gethostbyname(buf))<=0)
{
printf("error: gethostbyname\n");
exit(1);

Quote:}

bcopy(hp->h_addr,&self.sin_addr,hp->h_length);
//memcpy(&self.sin_addr, hp->h_addr, hp->h_length);
len=sizeof(struct sockaddr_in);

if(-1==(bind(sock,(struct sockaddr *)&self,len)))
{
printf("Error: bind \n");
exit(1);

Quote:}

their.sin_family=AF_INET;
their.sin_port=htons(2502);

if((sp=gethostbyname(argv[1]))<=0)
{
printf("Error: gethostbyname:their\n");
exit(1);

Quote:}

bcopy(sp->h_addr,(char *)&their.sin_addr,sp->h_length);

printf("Initially sending the size of the packet\n");
if((sendto(sock,&h1,sizeof(struct initval),0,(struct sockaddr
*)&their,len))<0)
{
printf("Error sending packet size\n");
exit(1);

Quote:}

lapse=0;
gettimeofday(&tstart,NULL);
printf("%ld \n",tstart.tv_sec,tstart.tv_usec);
while(k++<n)
{
p->pkt_no=cnt;
{
cnt++;
gettimeofday(&p->t1,NULL);
if((sendto(sock,p,pkt_size,0,(struct sockaddr *)&their,len))<0)
{
printf("error: sending packet\n");
Quote:}

if((recvfrom(sock,&p1,pkt_size,0,(struct sockaddr *)&their,&len))>0)
{
gettimeofday((&p1.t3),NULL);
pkts_received++;
lapse+=(p1.t3.tv_sec-p1.t1.tv_sec)*1000000+(p1.t3.tv_usec-p1.t1.tv_usec);
Quote:}
}
}

printf(" \n Number of packets received after round trip is
%ld",pkts_received);
//
lapse=(p1.t3.tv_sec-tstart.tv_sec)*1000000+(p1.t3.tv_usec-tstart.tv_usec);
printf("\n Total time taken for reception is %ld micro_secs\n",(lapse));
printf("\n Throughput is %f
bits/sec\n",(float)(pkt_size)*8*2*(pkts_received)*1000000/lapse);

Quote:}

once again, I will be grateful to you for suggestions.
best regards,
 
 
 

UDP throughput tool: unusually low throughput

Post by Grant Taylo » Sat, 15 Feb 2003 01:52:39



> wireless LAN (802.11b). I've written a piece of code (sender and
> receiver) that however, give me a throughput of only around 3Mbps
> Here's what my code does: the sender (client) sends UDP packets of a
> specified size (i generallyl give 1500 bytes becfause that's the largest
> MTU) and specified number (depending on the file size) to the receiver
> (server) which then sends it back to the sender.

Your code appears to be while(1) { send(); recv(); }, with blocking
sends and recvs.  Throughput will be a function of total latency, not
link speed.  3m is actually pretty good for this style of traffic!

Most streaming protocols use a "window", which is effectivly a number
of packets to keep outstanding at any one time; in TCP it is computed
as a function of round-trip timing information, packet loss, and a few
other things.

Rearrange your xmit program thusly:

while(window--) {
  send();

Quote:}

while(1) {
  if (recv() > 0) {
    send();
  }

Quote:}

Start with a window of 10 and experiment.  You may also wish to crank
the send and recv buffer sizes on your sockets; often the default size
is fairly small.

In general, it is hard to recommend development of a streaming
protocol over UDP unless it is critical for your application to avoid
one of TCP's "reliable, sequenced, bytestream" characteristics.  It's
also *very* unlikely that you will be able to approach TCP's level of
efficiency with a userspace implementation.

--
Grant Taylor - gtaylor<at>picante.com - http://www.picante.com/~gtaylor/
 Linux Printing Website and HOWTO:  http://www.linuxprinting.org/