300 likes | 442 Views
Assignment 4: Client Server Chatroom. SOCKET. socket creates an endpoint for communication. Two useful headers for socket programming: #include < signal.h > #include <sys/ socket.h >. Description. Server: support at most 10 clients one time Client:
E N D
SOCKET socket creates an endpoint for communication. Two useful headers for socket programming: #include <signal.h> #include <sys/socket.h>
Description • Server: • support at most 10 clients one time • Client: • will be asked for hostname for the server Eg. “rc01xcs213.managed.mst.edu” • Will be asked for a username (alias)
Chatroom Behavior • Basic: user in client type message and press enter; server will receive the message as well as other connected clients • Special Command: • User type /exit, /quit or /part, client exit; server print a message that client(alias) has left • User press ctrl+c, client print a nice error message to ask user to type /exit, /quit or /part • User press ctrl+c, server warns clients it will shut down in 10 seconds; clients receive warning message from server and exit; after 10 seconds, server shuts down.
Data Structures Server’s address Info: sockaddr_inhost ={AF_INET, htons(SERVER_PORT)} In the Internet address family, the SOCKADDR_IN structure is used by Windows Sockets to specify a local or remote endpoint address to which to connect a socket. An important aspect about SERVER_PORT is that all ports bellow 1024 are reserved. You can set a port above 1024 and bellow 65535 (unless the ones being used by other programs). htons(): host to network short Client’s address info: sockaddr_inpeer = {AF_INET} Thread for clients
Create New Socket socket() - creates an unbound socket in a communications domain, and return a file descriptor that can be used in later function calls that operate on sockets or return -1 on error. socket(int domain, int type, int protocol) domain-> communications domain in which a socket is to be created: AF_INET or AF_UNIX type -> type of socket to be created. (Stream or Datagram) protocol-> particular protocol to be used with the socket. protocol = 0 => use an unspecified default protocol appropriate for the requested socket type. Example: soc = socket(AF_INET, SOCK_STREAM, 0);
bind socket bind() – associate a socket with a port, returns -1 on error int bind(intsocket, const structsockaddr *address,socklen_taddress_len); socket -> file descriptor of the socket to be bound. address -> points to a sockaddr structure containing the address to be bound to the socket. address_len -> length of the sockaddr structure pointed to by the address argument. Example: Bind(soc, (sockaddr*)&host, sizeof(host))
listen for new connections listen() - listen for socket connections and limit the queue of incoming connections. int listen(int socket, int backlog) Backlog -> provides a hint to the implementation which the implementation shall use to limit the number of outstanding connections in the socket's listen queue. Example: listen(soc, 10)
Accept a new connection accept() - accepts a new connection on a socket int accept(intsocket, structsockaddr *restrict address, socklen_t *restrict address_len); Address -> Either a null pointer, or a pointer to a sockaddr structure where the address of the connecting socket shall be returned address_len- > Points to a socklen_t structure which on input specifies the length of the supplied sockaddr structure, and on output specifies the length of the stored address. Example: var = accept(soc, (sockaddr*)&peer, (socklen_t*)&peerlen);
create new thread for each connection Each client is handled using a seperate thread. pthread_create(&myThread, NULL, ClientHandler, &var);
Server Socket Setup Steps socket() bind() listen() accept() Mutex lock on client thread Set client ID’s from 1 to n pthread_create() for each client: read and write operations in client handler Unlock mutex
Read() • Data is taken out of a pipe • #include <unistd.h> • int read (intfile_desc, void * buffer, intnum_bytes) read up to num_bytes from file_desc and puts the data read info to buffer; returns the number of bytes read on success, otherwise a negative value is returened
Write() • Data is writen to a pipe • #include<unistd.h> • int write (intfile_desc, const void* buffer, intnum_bytes) write num_bytes bytes of data from buffer into file_desc; returns the number of bytes written on success, otherwise a negative value is returned.
Signals • Signals are notifications sent to processes to notify them of various events • By default, signals interrupt the receiving process immediately and force it to handle them • When a signal is received by a process: • The OS stops execution of the process • The OS forces the process to call the signal handler for the signal • When the handler is done the process picks up where it left off
Call Signal() • Specify a function to handle a specific signal • #include <signal.h> • Signal (intsig, fcn_name) To run function fcn_name when signal sig is raised; The new function handler must return void and take in a single int as an argument; The int argument will be assigned to the numeric value of the signal received;
Call signal(continue…) On success the signal function returns back a function pointer to the old handler for the specified signal, otherwise a negative value is returned. IMPORTANT: after a signal is caught the handler is returned back to the default handler signal(SIGINT, signalhandler); ctrl-c will raise SIGINT By default, SIGINT immediately terminates the process In the assignment, you specify your own function to be signalhandler
Ctrl-C signal handler SignalHandler(int sig) { Print message in server that it is shutting down; strcat to write buffer the message that server is shutting down and call the function to write all clients using this buffer; clear out all threads, close connections; sleep for 10 sec; exit; } Example: http://web.mst.edu/~ercal/284/SignalExamples/Samples.html
ClientHandler Declare arrays as read buffer, write buffer, userName Client will send a message containing its username(alias) first Write to the client using write buffer a welcome message: Eg: strncpy(writeBuf, "Welcome ", 8) Print to all clients that thisClient has entered the room
ClientHandler (continue…) The data that clients send is stored in read buffer Print read buffer data to server and all clients except thisClient If readbuffer data is special messages like ‘/exit, /quit or /part’ then print goodbye message to server and all clients remove this client from client array Exit
Writing to all clients allClientwrite() { Mutex lock the thread for client For all clients except thisClient Write the message stored in write buffer Unlock mutex }
Data Stuctures & functions Client structure: members – clientName clientId // ‘0’ initially Server’s address Info: structsockaddr_inhost = {AF_INET, htons(SERVER_PORT)}; Buffer – an array used for writing data void* EchoHandler(void * soc) – thread handler function void signalhandler(int sig) – if ctrl-c is pressed for client, it won’t let it exit, rather print message asking to type “/exit” or “/part” or “/quit”
Connect the client to the server Prompt to enter the hostname to which user wants to connect. Use gethostbyname() to save the hostname gethostbyname() is used to get its IP address and store it in a structin_addr Takes a string (like www.yahoo.com or rc01xcs213.managed.mst.edu) as parameter. Eg: hp = gethostbyname(argv[1]) Print an error message if return value is NULL (hostname does not exist) Then, enter the client’s username (alias) as required
Copy the host address into peer socket The bcopy() function shall copy n bytes from the area pointed to by s1 to the area pointed to by s2. bcopy(hp->h_addr_list[0], (char*)&peer.sin_addr, hp->h_length) Where host is saved by gethostbyname() in hp.
create a socket and connect to server socket() function to create a client socket Connect() to connect to the server, return -1 on error int connect(intsocket, const structsockaddr *address,socklen_taddress_len); socket -> Specifies the file descriptor associated with the socket. address -> Points to a sockaddr structure containing the peer address. The length and format of the address depend on the address family of the socket. address_len -> Specifies the length of the sockaddr structure pointed to by the address argument.
Ctrl+Csignalhandler() signal(SIGINT, signalhandler) ctrl-c will raise SIGINT By default, SIGINT immediately terminates the process In the assignment, you specify your own function to be signalhandler signalhandler(int sig) { On pressing ctrl-c on a client, it should prompt a nice error message to ask user to type /exit, /quit or /part instead of exit }
Threads for Client Create threads to handle read and write the client Thread for accept user input and check for exit condition Thread for echoing server message The thread handler function will take care of different errors and special messages to be printed. Example – pthread_create(&myThread, NULL, EchoHandler, &socket);
Operations of a Client write – write(soc, buffer, strlen(buffer)); read – read(soc, buffer, strlen(buffer)); Read buffer and check for different quitting conditions: in case it is writing “/exit” or “/quit” or “/part” , print goodbye message and exit If the server shutting down message is read from buffer, print “server is shutting” and exit