COMP445
Fall 2006
Lab assignment 1
CALLER
RECEIVER
STEP1: Get the name of the second party
STEP1: Plug the
phone, and listen
for incoming calls
on a certain line
STEP2: Get phone
number from white
pages
STEP3: Copy the
number for your
records
STEP4: Call the
other party
STEP2: Get a call
and accept it.
Caller ID will
give you the
callers phone
number.
Connection
Established.
Chat
2
Program architecture
Client
Server
port 7070
Socket Programming
Berkeley added a new interface to the operating system
to support network communication. This interface is
generally known as the Berkeley Sockets Interface and
is the basis for almost all existing TCP/IP network
protocol interfaces, including Windows Sockets
(commonly referred to as WinSock).
A socket is very much like a telephone - it's the endpoint
of a two-way communications channel. By connecting
two sockets together you can pass data between
processes running on different computers.
4
Main steps client side
Creating a socket
SOCKET socket(int domain, int type, int protocol);
s = socket(AF_INET,SOCK_STREAM,0)
The structure we fill in is defined below.
struct sockaddr_in {
short sin_family; // address family u_short
sin_port;// service port struct in_addr 16 bit TCP or UDP port number, network byte order
sin_addr; // internet address char 32 bits IPv4 address, Network Bytes Order
sin_zero[8]; // filler
}sa_in
Main steps client side
Client needs the address of the server.
User inputs the servers hostname.
rp=gethostbyname(remotehost)
Fill in the server address
memset(&sa_in,0,sizeof(sa_in));
memcpy(&sa_in.sin_addr,rp->h_addr,rp->h_length);
sa_in.sin_family = rp->h_addrtype;
sa_in.sin_port = htons(port); //port = 7070 host to network 16 bits
Connecting
if (connect(s,(LPSOCKADDR)&sa_in,sizeof(sa_in)) == SOCKET_ERROR)
throw "connect failed\n";
Sending frames
ibytessent = send(s, (char*)&message_frame,
sizeof(message_frame), 0);
Receiving frames
ibytesrecv = recv(s, (char*)& data_frame,
sizeof(data_frame),0)
6
Main steps server side
Creating a socket
s = socket(AF_INET,SOCK_STREAM,0)
Fill in the server port and address info
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
Bind the server port
if (bind(s,(LPSOCKADDR)&sa,sizeof(sa)) == SOCKET_ERROR)
Listen for client requests
if(listen(s,10) == SOCKET_ERROR)
Main steps server side
Watching for new messages
FD_SET(s,&readfds); //always check the listener
if(!(outfds=select(infds,&readfds,NULL,NULL,tp))) {}
else if (outfds == SOCKET_ERROR)
throw "failure in Select";
else if (FD_ISSET(s,&readfds))
cout << "got a connection request" << endl;
Accept the request
if((s1=accept(s,&ca.generic,&calen))==INVALID_SOCKET)
throw "Couldn't accept connection\n";
Read a message
if((ibytesrecv = recv(s1,szbuffer,128,0)) ==
SOCKET_ERROR)
Send a message
if((ibytessent = send(s1,szbuffer,ibufferlen,0))==
SOCKET_ERROR)
Socket Functions
int socket(int family, int type, int protocol);
returns: nonnegative descriptor if OK, -1 on error
int connect(int sockfd, const struct sockaddr * servaddr, int addrlen);
return:0 if OK -1 on error
int bind(int sockfd, const struct sockaddr * myaddr, int addrlen);
return: 0 if OK, -1 on error
int listen(int sockfd, int backlog);
return: 0 of OK, -1 on error
int accept(int sockfd, struct sockaddr * cliaddr, int * addrlen);
returns: nonnegative descriptor if OK,-1 on error
CLIENT
SERVER
PURPOSE: File Transfer
-Get a file
-Send a file
Should inform the server if
the required action is to get
a file from the server
to upload a file to the server.
Should specify the name of the
File.
Respond to possible error messages.
If a file is asked for, then it should
send an error message if file
doesnt exist.
If file exists, send it.
If file is being sent to you, save it.
10
Transferring the data in and
from the packet structure
Struct CONTROL_FRAME {
unsigned char direction;
char fname[MAX];
}
//GET or PUT
//filename
struct MESSAGE_FRAME {
unsigned char header; //ERROR,DATA,LASTPACKET, etc.
char data[MAX_SIZE]; //data or error message
} message_frame;
YOU ARE FREE TO DESIGN YOUR OWN STRUCTURES
11
Reading from a file
void main( void ) {
FILE *stream;
int numread, numwritten;
if( (stream = fopen( "fread.out", "r+b" )) != NULL ) {
numread = fread(message_frame.data,sizeof(char), MAX_SIZE, stream);
}
else
printf( "File could not be opened\n" );
}
fclose( stream );
}
Be careful if you use strcpy when reading from a binary file use memcpy.
12
Writing in a file
void main( void ) {
FILE *stream;
int numread, numwritten;
if( (stream = fopen( "fread.out", "w" )) != NULL ) {
numwritten = fwrite(szbuffer, sizeof(char), MAX_SIZE, stream );
}
else{
printf( "Problem opening the file\n" );
}
fclose( stream );
}
13
Decrypting the header
Use a switch to treat each of the cases:
switch (message_frame.header){
case 1
:
;
break;
case 2
:
;
break;
case 3
:
;
break;
default:
}
14
Hints
Use a log file in each side in order to
monitor all the actions:
receiving a packet
sending a packet, etc.
Open and close the log file after each
read/write operation if your program freezes
and you cannot read the log file.
Do not use any string library function! You
will be able to send only text files but not
binary ones (jpeg or exe for example).
Instead use memcpy for transferring data.
Do not care about the order of the receiving
packets in this assignment (TCP will do it for
you).
15
Assignment 1
No GUI
Use Visual C++ 6
Groups of NOT more than 2
wsock32.lib or you add the following
command to your code:
#pragma comment(lib,"wsock32.lib")
Implement only whatever youre asked to
do.
16
Multi-thread in Windows
uintptr_t _beginthread( void( __cdecl *start_address )( void * ), unsigned stack_size, void
*arglist );
Parameters:
start_address
Start address of routine that begins execution of new thread.
stack_size
Stack size for new thread or 0.
arglist
Argument list to be passed to new thread or NULL.
17
The C++ Thread Class provided to you
#define
STKSIZE 16536
class Thread{
public:Thread(){}
virtual ~Thread() {}
static void * pthread_callback (void * ptrThis);
virtual void run () =0 ;
void start();
};
void * Thread::pthread_callback (void * ptrThis) {
if ( ptrThis == NULL ) return NULL ;
Thread * ptr_this =(Thread *)(ptrThis) ;
ptr_this->run();
return NULL;
}
void Thread::start () {
int result;
if(( result = _beginthread((void (*)(void *))Thread::pthread_callback,STKSIZE,this ))<0)
{
printf("_beginthread error\n");
exit(-1);
}
}
18
How to make _beginthread work in VC6.00++
Right click the project and go to the Setting->C/C++->Category. Change the
Category to Code Generation and change Use run-time library to
Multithreaded.
Note:You will encounter such a error error C2065: '_beginthread' : undeclared
identifier at the compile time if you dont do the above setting.
19