1 / 20

Berkeley Sockets An example

Berkeley Sockets An example. Carsten Griwodz (adapted from lecture by Olav Lysne). Read and Write. The call read(sock, buffer, n); Reads n characters From socket sock Stores them in the character array buffer The call write(sock, buffer, n); Writes n characters

sona
Download Presentation

Berkeley Sockets An example

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Berkeley Sockets An example Carsten Griwodz (adapted from lecture by Olav Lysne) Socket example

  2. Read and Write • The call read(sock, buffer, n); • Reads n characters • From socket sock • Stores them in the character array buffer • The call write(sock, buffer, n); • Writes n characters • From character array buffer • To the socket sock Socket example

  3. Read and Write in TCP TCP sender • Typical • retval == -1 • Some kind of error, look at errno • Retval == 0 • The connection has been closed • Retval n < 2000 • You tried to send too fast • Only n bytes have been sent • Try sending the reset • Retval == 2000 • All bytes have been sent • Very untypical • Retval < -1 • Retval > 2000 • Both cases: • Have you used char retval instead of int retval? char buffer[2000]; int retval; buffer[0] = ‘a’; buffer[1] = ‘b’; buffer[2] = ‘c’; … /* write abcdefghij */ retval = write( sock, buffer, 2000 ); Socket example

  4. Read and Write in TCP TCP receiver • Typical • retval == -1 • Some kind of error, look at errno • Retval == 0 • The connection has been closed • Retval n < 2000 • Only n bytes have been received • No new data has arrived recently • Try sending the rest • Retval == 2000 • All bytes have been received • Very untypical • Retval < -1 • Retval > 2000 • Both cases: • Have you used char retval instead of int retval? char buffer[2000]; int retval; … /* write abcdefghij */ retval = read( sock, buffer, 2000 ); Socket example

  5. Application protocol chatting Chat client 1 Chat server Chat client 2 connection chat chat chat “#” disconnection Socket example

  6. Some detail • Port numbers are sent as 4 ASCII characters • Machine names are sent as • First 2 ASCII characters as a two digits decimal number indicating the number of bytes in the name • Then the name, in the number of bytes indicated before • A ”chatted” line is sent as 80 ASCII characters • When a user chats a line that starts with the character ’#’ the chat session ends Socket example

  7. Helper function for communication • It is worthwhile to put some socket functions into functions calls such that it becomes easier to use them • A call that provides a socket that listens to a given port • Hides bind, listen, struct sockaddr_in • A call that provides a socket that is connection to a given hostname and port number • Hides connect, name resolution, etc. • Several read and write operations Socket example

  8. Creation of a listen socket int TCPListenSocket(int port_number) { struct sockaddr_in serveraddr, clientaddr; int clientaddrlen; int request_sock; int i; /* Create the request socket. */ request_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (request_sock < 0) { printf("Creation of a socket failed.\n"); exit(1); } /* Fill in the address structure */ bzero((void *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = INADDR_ANY; serveraddr.sin_port = htons(port_number); /* Allow that the socket to reuse a port that the server * has also used when it was started before. Otherwise * TCP waits for a few minutes before allowing reuse. */ i = 1; setsockopt( request_sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); /* Bind the address to the socket. */ if (bind(request_sock, (struct sockaddr *)&serveraddr, sizeof serveraddr) < 0) { printf("Binding address to socket failed\n"); exit(1); } /* Start listening to the socket */ if (listen(request_sock, SOMAXCONN) < 0) { printf("Can't listen to the socket\n"); exit(1); } return request_sock; } Socket example

  9. Connection from the client side int TCPClientSocket(char machine[], int port_number) { struct hostent *hostp; struct sockaddr_in serveraddr; int sock; /* Create a socket */ if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { printf("Creation of a socket failed.\n"); exit(1); } /* Clean the serveraddr structure */ bzero((void *) &serveraddr, sizeof(serveraddr)); /* Initialize the serveraddr structure for the machine and port */ serveraddr.sin_family = AF_INET; /* Look in DNS for the IP address of the name */ if ((hostp = gethostbyname(machine)) == 0) { fprintf(stderr,"Ukjent machine %s\n",machine); exit(1); } /* Put the address into the serveraddr structure */ memcpy(&serveraddr.sin_addr, hostp->h_addr, hostp->h_length); /* Add the port number */ serveraddr.sin_port = htons(port_number); /* Connect to the other machine */ if (connect(sock, (struct sockaddr *)&serveraddr, sizeof serveraddr) < 0) { close(sock); printf("Can't connect to %s\n",machine); exit(1); } return sock; } Socket example

  10. Safe reading and writing /* Reads exactly l bytes from the socket */ int saferead(int so, char buf[], int l) { int i; for (i=0; i<l; i++) { buf[i]=safereadbyte(so); } return l; } /* Write to a socket in the same way as write, but returns an error message if the socket has been closed in the meantime */ int safewrite(int so, char buf[], int l) { int i; if (i=write(so, buf, l)==0) { printf("Can't write to socket, connection is closed" ); exit(1); } return i; } /* Reads exactly one byte from a socket connection */ char safereadbyte(int so) { int bytes; char buf[1]; bytes = read(so, buf, 1); /* Check whether the read worked */ if (bytes<0) { perror("Error in saferead"); if (close(so)) perror("close"); exit(1); } /* Check whether the connection is still open */ if (bytes==0) { printf("server: end of file on %d\n",so); if (close(so)) perror("close"); exit(1); } return buf[0]; } Socket example

  11. Server: connecting two clients int connect_two_clients(int listen_socket) { int client_socket1, client_socket2; struct sockaddr_in clientaddr1, clientaddr2; int clientaddrlen1, clientaddrlen2; char client_name1[80], client_name2[80]; char client_port1[5], client_port2[5]; char name_length1[3], name_length2[3]; memset( client_name1, 0, 80 ); memset( client_name2, 0, 80 ); memset( client_port1, 0, 5 ); memset( client_port2, 0, 5 ); memset( name_length1, 0, 3 ); memset( name_length2, 0, 3 ); /* Accept a connection from a first client */ clientaddrlen1 = sizeof(clientaddr1); client_socket1 = accept(listen_socket, (struct sockaddr *)&clientaddr1, &clientaddrlen1); if (client_socket1 < 0) perror("Can't accept connection from a first chat client\n" ); /* Read machine name and port number that client sends * as its contact information */ saferead(client_socket1, name_length1, 2); saferead(client_socket1, client_name1, atoi(name_length1)); saferead(client_socket1, client_port1, 4); /* Accept a connection from second client */ clientaddrlen2 = sizeof(clientaddr2); client_socket2 = accept(listen_socket, (struct sockaddr *)&clientaddr2, &clientaddrlen2); if (client_socket2 < 0) perror("Can't accept connection “ “from a second chat client\n" ); /* Read machine name and port number that client sends * as its contact information */ saferead(client_socket2, name_length2, 2); saferead(client_socket2, client_name2, atoi(name_length2)); saferead(client_socket2, client_port2, 4); Socket example

  12. Server: connecting two clients cntd. /* Tell the first client that it is the server in the chat * connection, and to wait for connection by a chat partner */ safewrite(client_socket1, "T", 1); /* Tell the second client that it is the client in the chat * connection, and to connect to the given name and port */ safewrite(client_socket2, "K", 1); safewrite(client_socket2, name_length1, 2); safewrite(client_socket2, client_name1, atoi(name_length1)); safewrite(client_socket2, client_port1, 4); /* Close the sockets for both clients */ close(client_socket1); close(client_socket2); return 0; } Socket example

  13. Server’s main function int main(int argc, char *argv[]) { int listen_socket; if( argc != 2 ) { fprintf(stderr,"Usage: %s <port number>\n", argv[0]); exit(1); } /* Start listening to the port number from the command * line */ listen_socket = TCPListenSocket(atoi(argv[1])); /* Connect pairs of clients forever */ while (1) connect_two_clients(listen_socket); /* We don't ever come here */ close(listen_socket); } Socket example

  14. Client: contacting the server int getchatpartner( char servername[], char serverport[], char myname[], char myport[] ) { int sock, listen_socket, partneraddresslength; struct sockaddr partneraddress; char name_length[3]; char client_or_server[2]; char chatpartnername[80]; char chatpartnerport[5]; char buf[80]; memset( name_length, 0, 3 ); memset( client_or_server, 0, 2 ); memset( chatpartnername, 0, 80 ); memset( chatpartnerport, 0, 5 ); /* Create a socket that is read to accept connections from * a chat partner */ listen_socket = TCPListenSocket(atoi(myport)); /* Connect to a chat server */ sock = TCPClientSocket(servername,atoi(serverport)); /* Tell the server how you can be contacted by a chat * partner */ sprintf(name_length, "%d", strlen(myname)); safewrite(sock, name_length, 2); safewrite(sock, myname, strlen(myname)); safewrite(sock, myport, 4); /* Receive from the server whether you will act as a client * or as a server in the chat */ saferead(sock, client_or_server, 1); Socket example

  15. Client: contacting the server cntd. if (client_or_server[0] == 'K') { /* You will be the client in the chat */ /* Close the socket that you would have * needed as a chat server */ close(listen_socket); /* Read the length of the chat partner's hostname */ saferead(sock, name_length, 2); /* Read the chat partner's hostname */ saferead(sock, chatpartnername, atoi(name_length)); /* Read the chat partner's port number */ saferead(sock, chatpartnerport, 4); /* Close the connection to the server */ close(sock); /* Connect to the chat partner */ sock = TCPClientSocket(chatpartnername, atoi(chatpartnerport)); /* Write to the screen that the user can talk first */ printf("Connection create, you talk first!!\n"); } else { /* Act as the server in the chat, no more information * is coming from the server */ close(sock); /* Accept a connection from a chat partner */ partneraddresslength = sizeof(partneraddress); sock = accept(listen_socket, (struct sockaddr *)&partneraddress, &partneraddresslength); if (sock < 0) perror("Error accepting connection from chat partner" ); /* Write to the screen that the chat partner talks first */ printf("Connection create, partner talks first!!\n"); saferead(sock, buf,80); printf(buf); } return sock; } Socket example

  16. Client: chatting and main /* A function that alternately reads a text string from * standard input and sends it over the TCP connection, and * receive a text string and prints it on the screen. */ int chat(int socket) { char text[80]; while (1) { fgets(text,80,stdin); write(socket,text, 80); if (text[0]=='#') return 0; saferead(socket, text,80); if (text[0]=='#') return 0; printf(text); } } int main(int argc, char *argv[]) { int sock; if( argc != 5 ) { fprintf( stderr, "Usage: %s <servername> <serverport> “ “<myname> <myport>\n", argv[0]); exit(1); } /* ask for a chart partner */ sock = getchatpartner(argv[1], argv[2], argv[3], argv[4]); /* chat along!*/ chat(sock); /* Close the chat socket */ close(sock); } Socket example

  17. Weaksnesses of the implementation • Server accounts hardly for wrong client behaviour • Sending characters when a post number is required • Client connects but does not send data, chat server ends • Server forwards simple what it receives, without checking that the machine name is the calling client’s • Chat client can only send in turns • That is different in a real chat session, or in real life • Everything that is typed should be sent, without an understanding of turns • Much more…! Socket example

  18. ”getchatpartner” begins as before… int getchatpartner( char servername[], char serverport[], char myname[], char myport[] ) { int sock, listen_socket, partneraddresslength; struct sockaddr partneraddress; char name_length[3]; char client_or_server[2]; char chatpartnername[80]; char chatpartnerport[5]; char buf[80]; memset( name_length, 0, 3 ); memset( client_or_server, 0, 2 ); memset( chatpartnername, 0, 80 ); memset( chatpartnerport, 0, 5 ); /* Create a socket that is read to accept connections from * a chat partner */ listen_socket = TCPListenSocket(atoi(myport)); /* Connect to a chat server */ sock = TCPClientSocket(servername,atoi(serverport)); /* Tell the server how you can be contacted by a chat * partner */ sprintf(name_length, "%d", strlen(myname)); safewrite(sock, name_length, 2); safewrite(sock, myname, strlen(myname)); safewrite(sock, myport, 4); /* Receive from the server whether you will act as a client * or as a server in the chat */ saferead(sock, client_or_server, 1); Socket example

  19. ...buts ends differently if (client_or_server[0] == 'K') { /* You will be the client in the chat */ /* Close the socket that you would have needed * as a chat server */ close(listen_socket); /* Read the length of the chat partner's hostname */ saferead(sock, name_length, 2); /* Read the chat partner's hostname */ saferead(sock, chatpartnername, atoi(name_length)); /* Read the chat partner's port number */ saferead(sock, chatpartnerport, 4); /* Close the connection to the server */ close(sock); /* Connect to the chat partner */ sock = TCPClientSocket(chatpartnername, atoi(chatpartnerport)); } else { /* Act as the server in the chat, no more information * is coming from the server */ close(sock); /* Accept a connection from a chat partner */ partneraddresslength = sizeof(partneraddress); sock = accept(listen_socket, (struct sockaddr *)&partneraddress, &partneraddresslength); if (sock < 0) perror("Error accepting connection from chat partner" ); } printf("Connection create, chat along!!\n"); return sock; } Socket example

  20. ”chat” function used separate processes for reading and writing, so that the don’t block each other: int chat(int socket) { int status; char text[10]; if (safefork()==0) { while (text[0] != '#') { fgets(text,80,stdin); write(socket,text, 80); } } else { while (text[0] != '#') { saferead(socket, text,80); printf(text); } } } int main(int argc, char *argv[]) { int sock; /* get a chat partner */ sock = getchatpartner(argv[1], argv[2], argv[3], argv[4]); /* start chatting */ chat(sock); /* close the chat socket */ close(sock); } Socket example

More Related