Prelimenary Research Report for TCP/IP - TIHLDE

gazecummingNetworking and Communications

Oct 26, 2013 (4 years and 13 days ago)

81 views


Prelimenary research report


TCP/IP and UDP/IP networking


1

TCP/IP and UDP/IP networking.

A preliminary research report.

Introduction

Before creating the network parts of the 3Dsnake game, project Largo, we decided to
do a preliminary research on how to do networking with sockets under Win32. This
document is the r
eport on the research we did, and is the basis for our further design
and development.


This document is solely targeted to the Largo project group, and therefore it contains
a lot of expressions that are considered ‘common knowledge’ in this group. For wo
rd
explanations I refer to our SRS.


We ended up using Winsock 1.1 instead of Winsock 2.0 solely because we found two
very simple and describing papers on the use of this API, and some source code that
we analyzed for our use. The functionality not include
d in the 1.1 version is not
something we need, so we are quite happy with that.


Trondheim, 25. January 2000

Rolv Seehuus

Preliminary

We did some decisions on the design even before we started the research. We wanted
to use the TCP/IP protocol to send cri
tical data like gamestate, new clients, clients
leaving and so forth, and use UDP for the actual gameplay data, like where in the
world are things located right now. There are several reasons for this, and here are the
most important ones:


-

TCP has acknowl
edging of packages. This is good for critical data, and in
the game there are several data of this kind. When the snake picks up a
package (the dots the snakes eat to grow, different powerups, etc), when a
snake leaves the game or enters the game, if a cli
ent is responding at all
and so forth.


-

UDP is not acknowledged, but the design and use is very similar, so
implementing both a UDP and TCP solution would not introduce a lot of
development overhead.

Sometimes we need the acknowledge, but when
it comes t
o data that are not absolutely crucial to functionality and that is
sent very often, like a snakes position and speed, we don’t need
acknowledge for every package. The game is a real
-
time application, so
we frankly don’t have time to sit around and wait fo
r acknowledgment on
all this packages now and then.




Prelimenary research report


TCP/IP and UDP/IP networking


2

-

A lot of games, like the Quake trilogy, Unreal and Unreal Tournament, use
this design. Theese are multi million selling games with huge success, and
there is a reason for that: Their designs are good.

Problem

In the beginning, the problem was quite blur: How do we send and receive packets
under Win32 with UDP and TCP? Our research led us around on the Internet
searching for good examples, and finally we found some really good ones right in our
backdoor:

The MSVS help system… The files are simples.c and simplec.c, witch are
included as appendix A and B.


The file simples.c is a simple TCP and UDP server implementation, witch we
analyzed thoroughly to learn how to do this serverside, and the simplec.c was

a simple
client implementation for the server. This analysis provided us with the knowledge on
how to implement a client/server system with TCP/IP and UDP/IP under windows,
and let us start on the design and implementation phase. These two examples used
W
insock 1.3,and that is the reason (as stated earlier) for why we decided to use this
API.


Conclusion

Now, after all this researching, we see that this is a lot simpler than we feared, and the
base network part of our game should be up and running in a fai
rly short amount of
time. The game logic and how the game will interact with the network is on the next
layer, and we believe that we can make a very general system for use in any real
-
time
networking system.


Prelimenary research report


TCP/IP and UDP/IP networking


3


Appendix A

/*********************************
*********************************************
\

* simplec.c
-

Simple TCP/UDP client using Winsock 1.1

*

* This is a part of the Microsoft Source Code Samples.

* Copyright 1996
-
1997 Microsoft Corporation.

* All rights reserved.

* Thi
s source code is only intended as a supplement to

* Microsoft Development Tools and/or WinHelp documentation.

* See these sources for detailed information regarding the

* Microsoft samples programs.

\
**************************************
****************************************/


#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>


#define DEFAULT_PORT 5001

#define DEFAULT_PROTO SOCK_STREAM // TCP


void Usage(char *progname) {


fprin
tf(stderr,"Usage
\
n%s
-
p [protocol]
-
n [server]
-
e [endpoint]
\


-
l [iterations]
\
n",



progname);


fprintf(stderr,"Where:
\
n
\
tprotocol is one of TCP or UDP
\
n");


fprintf(stderr,"
\
tserver is the IP address or name of server
\
n");


fprintf(stderr,"
\
tendpoint is

the port to listen on
\
n");


fprintf(stderr,"
\
titerations is the number of loops to execute
\
n");


fprintf(stderr,"
\
t(
-
l by itself makes client run in an infinite loop,");


fprintf(stderr," Hit Ctrl
-
C to terminate it)
\
n");


fprintf(stderr,"Defaults are TCP
, localhost and 5001
\
n");


WSACleanup();


exit(1);

}

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



char Buffer[128];


char *server_name= "localhost";


unsigned short port = DEFAULT_PORT;


int retval, loopflag=0;


int i, loopcount,maxloop=
-
1;


unsigned int addr;


int

socket_type = DEFAULT_PROTO;


struct sockaddr_in server;


struct hostent *hp;


WSADATA wsaData;


SOCKET conn_socket;



if (argc >1) {



for(i=1;i <argc;i++) {




if ( (argv[i][0] == '
-
') || (argv[i][0] == '/') ) {





switch(tolower(argv[i][1])) {






c
ase 'p':







if (!stricmp(argv[i+1], "TCP") )








socket_type = SOCK_STREAM;







else if (!stricmp(argv[i+1], "UDP") )








socket_type = SOCK_DGRAM;







else








Usage(argv[0]);







i++;







break;







case 'n':







server_name = arg
v[++i];







break;






case 'e':


Prelimenary research report


TCP/IP and UDP/IP networking


4







port = atoi(argv[++i]);







break;






case 'l':







loopflag =1;







if (argv[i+1]) {








if (argv[i+1][0] != '
-
')









maxloop = atoi(argv[i+1]);







}







else








maxloop =
-
1;







i++;







break;






default:







Usage(argv[0]);







break;





}




}




else





Usage(argv[0]);



}


}




if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {



fprintf(stderr,"WSAStartup failed with error %d
\
n",WSAGetLastError());



WSACleanup();



retur
n
-
1;


}




if (port == 0){



Usage(argv[0]);


}



//


// Attempt to detect if we should call gethostbyname() or


// gethostbyaddr()



if (isalpha(server_name[0])) { /* server address is a name */



hp = gethostbyname(server_name);


}


else { /* Convert

nnn.nnn address to a usable one */



addr = inet_addr(server_name);



hp = gethostbyaddr((char *)&addr,4,AF_INET);


}


if (hp == NULL ) {



fprintf(stderr,"Client: Cannot resolve address [%s]: Error %d
\
n",




server_name,WSAGetLastError());



WSACleanup()
;



exit(1);


}



//


// Copy the resolved information into the sockaddr_in structure


//


memset(&server,0,sizeof(server));


memcpy(&(server.sin_addr),hp
-
>h_addr,hp
-
>h_length);


server.sin_family = hp
-
>h_addrtype;


server.sin_port = htons(port);



conn_so
cket = socket(AF_INET,socket_type,0); /* Open a socket */


if (conn_socket <0 ) {



fprintf(stderr,"Client: Error Opening socket: Error %d
\
n",




WSAGetLastError());



WSACleanup();



return
-
1;


}



//


// Notice that nothing in this code is specific to w
hether we


// are using UDP or TCP.


// We achieve this by using a simple trick.


// When connect() is called on a datagram socket, it does not


Prelimenary research report


TCP/IP and UDP/IP networking


5


// actually establish the connection as a stream (TCP) socket


// would. Instead, TCP/IP establishes

the remote half of the


// ( LocalIPAddress, LocalPort, RemoteIP, RemotePort) mapping.


// This enables us to use send() and recv() on datagram sockets,


// instead of recvfrom() and sendto()




printf("Client connecting to: %s
\
n",hp
-
>h_name);


i
f (connect(conn_socket,(struct sockaddr*)&server,sizeof(server))



== SOCKET_ERROR) {



fprintf(stderr,"connect() failed: %d
\
n",WSAGetLastError());



WSACleanup();



return
-
1;


}



// cook up a string to send


//


loopcount =0;


while(1) {



wsprintf(Buff
er,"This is a small test message [number
%d]",loopcount++);



retval = send(conn_socket,Buffer,sizeof(Buffer),0);



if (retval == SOCKET_ERROR) {




fprintf(stderr,"send() failed: error %d
\
n",WSAGetLastError());




WSACleanup();




return
-
1;



}



printf(
"Sent Data [%s]
\
n",Buffer);



retval = recv(conn_socket,Buffer,sizeof (Buffer),0 );



if (retval == SOCKET_ERROR) {




fprintf(stderr,"recv() failed: error %d
\
n",WSAGetLastError());




closesocket(conn_socket);




WSACleanup();




return
-
1;



}



//



//
We are not likely to see this with UDP, since there is no



// 'connection' established.



//



if (retval == 0) {




printf("Server closed connection
\
n");




closesocket(conn_socket);




WSACleanup();




return
-
1;



}



printf("Received %d bytes, data [
%s] from server
\
n",retval,Buffer);



if (!loopflag){




printf("Terminating connection
\
n");




break;



}



else {




if ( (loopcount >= maxloop) && (maxloop >0) )





break;



}


}


closesocket(conn_socket);


WSACleanup();

}


Prelimenary research report


TCP/IP and UDP/IP networking


6


Appendix B

/****************
**************************************************************
\

* simples.c
-

Simple TCP/UDP server using Winsock 1.1

* This is a part of the Microsoft Source Code Samples.

* Copyright 1996
-
1997 Microsoft Corporation.

* All rights reserve
d.

* This source code is only intended as a supplement to

* Microsoft Development Tools and/or WinHelp documentation.

* See these sources for detailed information regarding the

* Microsoft samples programs.

\
************************
******************************************************/


#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>


#define DEFAULT_PORT 5001

#define DEFAULT_PROTO SOCK_STREAM // TCP


void Usage(char *prog
name) {


fprintf(stderr,"Usage
\
n%s
-
p [protocol]
-
e [endpoint]
-
i [interface]
\
n",



progname);


fprintf(stderr,"Where:
\
n
\
tprotocol is one of TCP or UDP
\
n");


fprintf(stderr,"
\
tendpoint is the port to listen on
\
n");


fprintf(stderr,"
\
tinterface is the ipadd
r (in dotted decimal notation)");


fprintf(stderr," to bind to
\
n");


fprintf(stderr,"Defaults are TCP,5001 and INADDR_ANY
\
n");


WSACleanup();


exit(1);

}

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



char Buffer[128];


char *interface= NULL;


unsigned short port=DEF
AULT_PORT;


int retval;


int fromlen;


int i;


int socket_type = DEFAULT_PROTO;


struct sockaddr_in local, from;


WSADATA wsaData;


SOCKET listen_socket, msgsock;



/* Parse arguments */


if (argc >1) {



for(i=1;i <argc;i++) {




if ( (argv[i][0] == '
-
')
|| (argv[i][0] == '/') ) {





switch(tolower(argv[i][1])) {






case 'p':







if (!stricmp(argv[i+1], "TCP") )








socket_type = SOCK_STREAM;







else if (!stricmp(argv[i+1], "UDP") )








socket_type = SOCK_DGRAM;







else








Usage(argv[0
]);







i++;







break;







case 'i':







interface = argv[++i];







break;






case 'e':







port = atoi(argv[++i]);







break;






default:







Usage(argv[0]);


Prelimenary research report


TCP/IP and UDP/IP networking


7







break;





}




}




else





Usage(argv[0]);



}


}




if (WSAStartup
(0x202,&wsaData) == SOCKET_ERROR) {



fprintf(stderr,"WSAStartup failed with error %d
\
n",WSAGetLastError());



WSACleanup();



return
-
1;


}





if (port == 0){



Usage(argv[0]);


}



local.sin_family = AF_INET;


local.sin_addr.s_addr = (!interface)?INADDR
_ANY:inet_addr(interface);



/*



* Port MUST be in Network Byte Order



*/


local.sin_port = htons(port);



listen_socket = socket(AF_INET, socket_type,0); // TCP socket




if (listen_socket == INVALID_SOCKET){



fprintf(stderr,"socket() failed with err
or %d
\
n",WSAGetLastError());



WSACleanup();



return
-
1;


}


//


// bind() associates a local address and port combination with the


// socket just created. This is most useful when the application is a


// server that has a well
-
known port that clients
know about in advance.


//



if (bind(listen_socket,(struct sockaddr*)&local,sizeof(local) )



== SOCKET_ERROR) {



fprintf(stderr,"bind() failed with error %d
\
n",WSAGetLastError());



WSACleanup();



return
-
1;


}



//


// So far, everything we did was a
pplicable to TCP as well as UDP.


// However, there are certain steps that do not work when the server is


// using UDP.


//



// We cannot listen() on a UDP socket.



if (socket_type != SOCK_DGRAM) {



if (listen(listen_socket,5) == SOCKET_ERROR) {




fpr
intf(stderr,"listen() failed with error
%d
\
n",WSAGetLastError());




WSACleanup();




return
-
1;



}


}


printf("%s: 'Listening' on port %d, protocol %s
\
n",argv[0],port,



(socket_type == SOCK_STREAM)?"TCP":"UDP");


while(1) {



fromlen =sizeof(from);



//



// accept() doesn't make sense on UDP, since we do not listen()



//



if (socket_type != SOCK_DGRAM) {


Prelimenary research report


TCP/IP and UDP/IP networking


8




msgsock = accept(listen_socket,(struct sockaddr*)&from,
&fromlen);




if (msgsock == INVALID_SOCKET) {





fprintf(stderr,"accept() error %d
\
n",WS
AGetLastError());





WSACleanup();





return
-
1;




}




printf("accepted connection from %s, port %d
\
n",







inet_ntoa(from.sin_addr),







htons(from.sin_port)) ;







}



else




msgsock = listen_socket;




//



// In the case of SOCK_STREAM, the

server can do recv() and



// send() on the accepted socket and then close it.




// However, for SOCK_DGRAM (UDP), the server will do



// recvfrom() and sendto() in a loop.




if (socket_type != SOCK_DGRAM)




retval = recv(msgsock,Buffer,sizeof (Buff
er),0 );



else {




retval = recvfrom(msgsock,Buffer,sizeof (Buffer),0,





(struct sockaddr *)&from,&fromlen);




printf("Received datagram from %s
\
n",inet_ntoa(from.sin_addr));



}







if (retval == SOCKET_ERROR) {




fprintf(stderr,"recv() failed: er
ror %d
\
n",WSAGetLastError());




closesocket(msgsock);




continue;



}



if (retval == 0) {




printf("Client closed connection
\
n");




closesocket(msgsock);




continue;



}



printf("Received %d bytes, data [%s] from client
\
n",retval,Buffer);




printf(
"Echoing same data back to client
\
n");



if (socket_type != SOCK_DGRAM)




retval = send(msgsock,Buffer,sizeof(Buffer),0);



else




retval = sendto(msgsock,Buffer,sizeof (Buffer),0,





(struct sockaddr *)&from,fromlen);



if (retval == SOCKET_ERROR) {




fprintf(stderr,"send() failed: error %d
\
n",WSAGetLastError());



}



if (socket_type != SOCK_DGRAM){




printf("Terminating connection
\
n");




closesocket(msgsock);



}



else




printf("UDP server looping back for more requests
\
n");



continue;


}

}