Title: Berkeley Sockets An example
1Berkeley Sockets An example
- Carsten Griwodz
- (adapted from lecture by Olav Lysne)
2Read 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
3Read 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 lt 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 lt -1
- Retval gt 2000
- Both cases
- Have you used char retval instead of int retval?
char buffer2000 int retval buffer0
a buffer1 b buffer2 c /
write abcdefghij / retval write( sock, buffer,
2000 )
4Read 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 lt 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 lt -1
- Retval gt 2000
- Both cases
- Have you used char retval instead of int retval?
char buffer2000 int retval / write
abcdefghij / retval read( sock, buffer, 2000 )
5Application protocol chatting
Chat client 1
Chat server
Chat client 2
connection
chat
chat
chat
disconnection
6Some 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
7Helper 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
8Creation of a listen socket
/ 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) lt 0)
printf("Binding address to socket
failed\n") exit(1) / Start
listening to the socket / if
(listen(request_sock, SOMAXCONN) lt 0)
printf("Can't listen to the socket\n")
exit(1) return request_sock
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 lt 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)
9Connection 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)) lt 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-gth_addr, hostp-gth_length) / Add the
port number / serveraddr.sin_port
htons(port_number) / Connect to the other
machine / if (connect(sock, (struct sockaddr
)serveraddr,
sizeof serveraddr) lt 0)
close(sock) printf("Can't connect to
s\n",machine) exit(1) return
sock
10Safe reading and writing
/ Reads exactly l bytes from the socket / int
saferead(int so, char buf, int l) int i
for (i0 iltl i)
bufisafereadbyte(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
(iwrite(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 buf1 bytes read(so, buf,
1) / Check whether the read worked /
if (byteslt0) perror("Error in
saferead") if (close(so))
perror("close") exit(1) /
Check whether the connection is still open /
if (bytes0) printf("server end
of file on d\n",so) if (close(so))
perror("close") exit(1)
return buf0
11Server 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_name180, client_name280 char
client_port15, client_port25 char
name_length13, name_length23 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 lt 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 lt 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_soc
ket2, name_length2, 2) saferead(client_socket
2, client_name2, atoi(name_length2))
saferead(client_socket2, client_port2, 4)
12Server 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_socket
2, "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
13Servers main function
int main(int argc, char argv) int
listen_socket if( argc ! 2 )
fprintf(stderr,"Usage s ltport numbergt\n",
argv0) exit(1) / Start
listening to the port number from the command
line / listen_socket TCPListenSocket(ato
i(argv1)) / Connect pairs of clients
forever / while (1) connect_two_clients(liste
n_socket) / We don't ever come here /
close(listen_socket)
14Client contacting the server
/ 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)
int getchatpartner( char servername, char
serverport, char
myname, char myport ) int sock,
listen_socket, partneraddresslength struct
sockaddr partneraddress char
name_length3 char client_or_server2
char chatpartnername80 char
chatpartnerport5 char buf80
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))
15Client contacting the server cntd.
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 lt 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
if (client_or_server0 '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(chatpart
nername,
atoi(chatpartnerport)) / Write to
the screen that the user can talk first /
printf("Connection create, you talk
first!!\n")
16Client chatting and main
int main(int argc, char argv) int sock
if( argc ! 5 ) fprintf( stderr,
"Usage s ltservernamegt ltserverportgt
ltmynamegt ltmyportgt\n", argv0)
exit(1) / ask for a chart partner /
sock getchatpartner(argv1, argv2, argv3,
argv4) / chat along!/ chat(sock) /
Close the chat socket / close(sock)
/ 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 text80 while (1)
fgets(text,80,stdin)
write(socket,text, 80) if (text0'')
return 0 saferead(socket, text,80)
if (text0'') return 0
printf(text)
17Weaksnesses 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
clients - 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!
18getchatpartner begins as before
/ 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)
int getchatpartner( char servername, char
serverport, char
myname, char myport ) int sock,
listen_socket, partneraddresslength struct
sockaddr partneraddress char
name_length3 char client_or_server2
char chatpartnername80 char
chatpartnerport5 char buf80
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))
19...buts ends differently
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 lt 0)
perror("Error accepting connection from
chat partner" ) printf("Connection
create, chat along!!\n") return sock
if (client_or_server0 '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(chatpart
nername,
atoi(chatpartnerport))
20chat function used separate processes for
reading and writing, so that the dont block each
other
int main(int argc, char argv) int
sock / get a chat partner / sock
getchatpartner(argv1, argv2, argv3,
argv4) / start chatting /
chat(sock) / close the chat socket /
close(sock)
int chat(int socket) int status char
text10 if (safefork()0) while
(text0 ! '')
fgets(text,80,stdin)
write(socket,text, 80) else
while (text0 ! '')
saferead(socket, text,80)
printf(text)