190 likes | 315 Views
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.
E N D
COMP445Fall 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 STEP2: Get a call and accept it. “Caller ID” will give you the caller’s phone number. STEP3: Copy the number for your records Connection Established. Chat… STEP4: Call the other party
Program architecture Server port 7070 Client
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.
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 ordersin_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 server’s 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 = 7070host 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)
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 doesn’t exist. • If file exists, send it. • If file is being sent to you, save it.
Transferring the data in and from the packet structure Struct CONTROL_FRAME { unsigned char direction; //GET or PUT char fname[MAX]; //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
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.
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 ); }
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: … }
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).
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 you’re asked to do.
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.
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); } }
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 don’t do the above setting.