Appendix F contains the code listing for the UDP-based
file transmission programs mentioned in Chapter 2.
// *********************************
// * UDP-based File Transfer Server
// * Filename: UDPserver.c
// *********************************
#include <stdio.h>
#include <windows.h>
#include <io.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#define MYPORT 8080
#define MPEG_FILE "test.mpg"
#define BLOCK 1024
int net_init();
void render_MPEG(SOCKET sd);
int open_MPEG(int* fdptr);
void sleep(clock_t wait);
struct UDP_packet { // defining my own packet
int seqnum;
char payload[BLOCK];
};
void main(void) {
int sd;
if ( (sd = net_init()) < 0 )
exit(0);
render_MPEG(sd);
closesocket(sd);
WSACleanup();
}
// FUNCTION net_init initializes connectionless oriented sockets -- UDP!
int net_init() {
int sd;
struct sockaddr_in myaddr;
WSADATA WsaData;
WORD wVersionRequested;
int err;
wVersionRequested = MAKEWORD(1, 1);
if ( (err = WSAStartup(wVersionRequested, &WsaData)) != 0 ) {
printf("Could not find WinSock 1.1 DLL\n");
return -1;
}
if ( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))
== INVALID_SOCKET) {
printf("socket error %d\n", WSAGetLastError());
return -1;
}
// bind it!!
memset( (char *)&myaddr, 0x00, sizeof(myaddr) );
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(MYPORT);
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sd, (struct sockaddr *)&myaddr, sizeof(myaddr))
== SOCKET_ERROR) {
printf("Bind error %d\n", WSAGetLastError());
return -1;
}
return sd;
}
//FUNCTION render_MPEG transmits MPEG data to client
void render_MPEG(SOCKET sd) {
int recvN, sendN, addrlen;
int fd, filesize, nread;
struct sockaddr_in clientaddr;
char *r_buffer, *s_buffer;
BYTE terminator;
int c=0, i=0, datasize=0, x;
struct UDP_packet my_packet;
clock_t start_t, stop_t; // for timing the transmission
double duration;
addrlen = sizeof(clientaddr);
my_packet.seqnum = 0; // initially
// each time server recvs, it's a request!
printf("Waiting to recv from client...\n");
r_buffer = (char *)malloc(BLOCK);
addrlen = sizeof(clientaddr);
recvN = recvfrom(sd, r_buffer, BLOCK, 0,
(struct sockaddr *)&clientaddr, &addrlen);
if (recvN == SOCKET_ERROR) {
printf("recvfrom error %d\n", WSAGetLastError());
return;
}
// open the file
if ( (filesize = open_MPEG(&fd)) < 0)
return;
s_buffer = (char *)malloc(BLOCK);
start_t = clock();
// send out MPEG data
while (filesize-c != 0) {
if ( (nread = _read(fd, my_packet.payload, BLOCK)) < 0 ) {
printf("_read error %d\n", errno);
return;
}
c += nread; // keep track of how many bytes read
fr file
x = sizeof(my_packet.seqnum);
sendN = sendto(sd, (char *)&my_packet, nread+x, 0,
(struct sockaddr *)&clientaddr, addrlen);
if (sendN == SOCKET_ERROR) {
printf("sendto error %d\n", WSAGetLastError());
return;
}
i = nread+x; // total supposed to have been sent out, vs sendN
datasize += sendN-x; //bytes of MPEG file already
sent out
if ( sendN != i) {
printf("Eeek!! bytes actually sent diff %d vs %d\n", i, sendN);
break;
}
my_packet.seqnum++; // next pkt's seqnum
}//end while
_close(fd);
stop_t = clock();
duration = (double)(stop_t-start_t)/CLOCKS_PER_SEC;
printf("Total packets sent: %d\n", my_packet.seqnum);
printf("Total %d bytes of MPEG data sent\n", datasize);
printf("Time taken %2.2f\n", duration);
printf("Now sending a terminator\n");
// send a byte of value 0x0000 to indicate termination
terminator = 0xff;
my_packet.payload[0] = terminator;
sendN = sendto(sd, (char *)&my_packet,
sizeof(BYTE)+sizeof(my_packet.seqnum), 0,
(struct sockaddr *)&clientaddr, addrlen);
if (sendN == SOCKET_ERROR)
printf("sendto error %d\n", WSAGetLastError());
}
// FUNCTION open_MPEG opens file, assigns a descriptor
// and returns filesize
int open_MPEG(int* fdptr) {
struct _stat file_stat;
if (_stat(MPEG_FILE, &file_stat) < 0) {
if (errno == ENOENT)
printf("File %s not found\n");
else
printf("_stat error unknown %d\n", errno);
return -1;
}
if ( (*fdptr = _open(MPEG_FILE, _O_RDONLY|_O_BINARY)) == -1 ) {
printf("_open error %d on file %s\n", errno, MPEG_FILE);
return -1;
}
return file_stat.st_size;
}
// FUNCTION sleep pauses for a specified number of seconds
void sleep(clock_t wait) {
clock_t goal;
goal = wait + clock();
while (goal > clock())
;
}
// *********************************
// * UDP-based File Transfer Client
// * Filename: UDPclient.c
// *********************************
#include <stdio.h>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#define SERVER_PORT 8080
#define MY_PORT 6969
#define BLOCK 1024
#define MPEG_REQUEST "REQUEST"
#define MPEG_REQUEST_COMPLETE 0xff
#define RECORD "events.txt"
int net_init();
void get_MPEG(SOCKET sd, char *filename);
int open_MPEGfile(char *filename);
// define my own packet -- use it to recv incoming UDP packets
struct UDP_packet {
int seqnum;
char payload[BLOCK];
};
char SERVER_HOST[20];
void main(int argc, char *argv[]) {
int sd;
char filename[20];
if(argc < 2) {
printf("Usage: UDPtestClient [IPaddress]\n");
exit(0);
}
strcpy(SERVER_HOST, argv[1]);
printf("Enter a filename not more than 20 characters.\nIt must end with .mpg: ");
scanf("%s", filename);
if ( (sd = net_init()) < 0 ) {
closesocket(sd);
exit(0);
}
get_MPEG(sd, filename);
closesocket(sd);
WSACleanup();
}
int net_init() {
int sd;
struct sockaddr_in myaddr;
WSADATA WsaData;
WORD wVersionRequested;
int err;
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &WsaData);
if (err != 0) {
printf("Could not find WinSock 1.1 DLL\n");
return -1;
}
if ( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))
== INVALID_SOCKET ) {
printf("socket error %d\n", WSAGetLastError());
return -1;
}
// client must bind itself!!
ZeroMemory((char *)&myaddr, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(MY_PORT);
if (bind(sd, (struct sockaddr *)&myaddr, sizeof(myaddr)) == SOCKET_ERROR) {
printf("client bind error %d\n", WSAGetLastError());
return -1;
}
return sd;
}
void get_MPEG(SOCKET sd, char *filename) {
int sendN, recvN, slen;
int fd, nwrite;
struct sockaddr_in servaddr;
char *s_buffer, *r_buffer;
int bytecount=0, c=0, x, prev_seqnum=-1, pktcount=0, lostpkt=0;
FILE *fp;
clock_t start_t, stop_t; // use for timing
double duration;
struct UDP_packet my_packet;
my_packet.seqnum = 0; // initially
// server's addr, etc !!
ZeroMemory((char *)&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(SERVER_HOST);
servaddr.sin_port = htons(SERVER_PORT);
slen = sizeof(servaddr);
s_buffer = (char *)malloc(BLOCK);
sprintf(s_buffer, MPEG_REQUEST);
sendN = sendto(sd, s_buffer, strlen(s_buffer), 0,
(struct sockaddr *)&servaddr, sizeof(servaddr));
if (sendN == SOCKET_ERROR) {
printf("sendto error %d\n", WSAGetLastError());
return;
}
// open MPEG file
if ( (fd = open_MPEGfile(filename)) < 0)
return;
// also open a file to record events
if ( (fp = fopen(RECORD, "a+")) == NULL ) {
printf("Can't open file %s\n", RECORD);
return;
}
else
fprintf(fp, "MPEG file: %s\n", filename);
r_buffer = (char *)malloc(BLOCK);
start_t = clock();
// start recving data
while (1) {
if ( (recvN = recvfrom(sd, (char*)&my_packet,
BLOCK+sizeof(my_packet.seqnum), 0,
(struct sockaddr *)&servaddr, &slen)) == SOCKET_ERROR ) {
printf("recvfrom error %d\n", WSAGetLastError());
_close(fd);
return;
}
// packet loss encountered! Keep track of it
if (my_packet.seqnum != prev_seqnum+1) {
fprintf(fp, "Current pkt #%d not in sequence with prev pkt #%d\n",
my_packet.seqnum, prev_seqnum); // write to events file
// keeps track of lost pkts
lostpkt += my_packet.seqnum-(prev_seqnum+1);
}
pktcount++; // keeps track of total pkt recvd
if (recvN == sizeof(BYTE)+sizeof(my_packet.seqnum)) {
if (my_packet.payload[0] == 0xff) {
printf("Done!\n"); // recvd a terminator
break;
}
else {
printf("Hmmm ... seqnum%d\n", my_packet.seqnum);
break;
}
}
x = sizeof(my_packet.seqnum);
c += recvN - x;
if ( (nwrite = _write(fd, my_packet.payload, recvN-x)) < 0) {
printf("_write error %d\n", errno);
_close(fd);
return;
}
bytecount += nwrite;
if (c != bytecount) {
printf("total bytes recvd (%d) and written (%d) different\n", c,
bytecount);
break;
}
prev_seqnum = my_packet.seqnum;
} // end while
_close(fd);
stop_t = clock();
duration = (double)(stop_t-start_t)/CLOCKS_PER_SEC;
printf("Total pkts accounted for: %d\n", pktcount);
printf("Packets lost: %d\n", lostpkt);
printf("Total of %d bytes written to file\n", bytecount);
printf("Time taken %2.2f\n", duration);
// writing more statistical info to events file
fprintf(fp, "Total pkts received: %d\n", pktcount);
fprintf(fp, "Number of packets lost: %d\n", lostpkt);
fprintf(fp, "Total of %d bytes received\n", bytecount);
fprintf(fp, "Time taken: %2.2f seconds\n", duration);
fprintf(fp, "=======================================\n");
fclose(fp);
}
// FUNCTION open_MPEGfile opens the file & returns its descriptor
// returns -1 if failed
int open_MPEGfile(char *filename) {
int fd;
fd = _open(filename, _O_CREAT|_O_TRUNC|_O_RDWR|_O_BINARY,
_S_IREAD|_S_IWRITE);
if (fd < 0) {
printf("_open error %d on file %s\n", errno, filename);
return -1;
}
return fd;
}