Network Programming Week #1 K.C. Kim kckim@konkuk.ac.kr
How do we communicate? Mail Example 1. Write a mail 2. Put the mail into a mailbox 3. Post office classify mails based on the address 4. Cars, airplanes or ships deliver the mail 5. End post office classify mails based on the address 6. Post man put the mail into a mailbox 7. Read a mail
Mail Example Mail contents - Application data Envelope format - TCP/IP header format Envelope address - TCP/IP Address Car, Postman, Train - Physical, Link Layer Distributing Post Office - Network Node(router, switch) Post Office - End host Post Box - Socket
Socket API Introduced in 1980 s(bsd 4.2) Inter process communication Network Application Programming Interface between net-application and net-protocols Includes TCP/IP protocol suite What is socket? A host-local, application-created, OS-controlled interface Application Network API Protocol A Protocol B Protocol C
Socket is a interface of Protocol Layered View bridge between application layer and kernel protocol layers To the kernel, a socket is an endpoint of communication. To an application, a socket is a file descriptor that lets the application read/write from/to the network End-to-end connection View Abstract representation of a communication endpoint Identified by protocol and local/remote address/port A socket is accessed by socket descriptor Once configured, the application can pass data to the socket for network transmission receive data from the socket (transmitted through the network by some other host)
Unix Descriptor Table 0 1 2 3 4 Descriptor Table Data structure for file 0 Data structure for file 1 Family: PF_INET Service: SOCK_STREAM Local IP: 111.22.3.4 Remote IP: 123.45.6.78 Local Port: 2249 Remote Port: 3726
Socket Process (simplified) 1. Create socket instance TCP or UDP 2. Assign address infos to the socket IP address, port number 3. Send (receive) data to (from) endpoint through the socket send(), recv()
Creating a Socket int socket(int family,int type,int proto); create a resource for communication endpoint just creates the interface! (no interface infos.) Family Type Protocol TCP SOCK_STREAM IPPROTO_TCP PF_INET UDP SOCK_DGRAM IPPROTO_UDP Socket reference File (socket) descriptor in UNIX Socket handle in WinSock Return value Socket descriptor number Positive value on success, -1 on error
Two essential types of sockets SOCK_STREAM a.k.a. TCP reliable delivery in-order guaranteed connection-oriented bidirectional SOCK_DGRAM a.k.a. UDP unreliable delivery no order guarantees no notion of connection app indicates dest. for each packet can send or receive
Data Sending int main() { int fd; fd = open( "data.dat", O_RDONLY,0); while( 1 ) { write( fd, test,sizeof( test )+1 ); } close( out ); return 0; } int main() { int sockfd; sd = socket( PF_INET, SOCK_STREAM,0); while( 1 ) { write( sd, test,sizeof( test )+1 ); } close( out ); return 0; } To where???? To where??
Assign an Endpoints Addrs. Sockets API is generic. There must be a generic way to specify endpoint addresses. TCP/IP requires an IP address and a port number for each endpoint address We will deal with only TCP/IP suite Other protocol suites (families) may use other schemes So we use sockaddr_in struct type instead of sockaddr struct type
Socket addresses IP address Ports Used to identify services on a host well-known (port 0-1023) dynamic or private (port 1024-65535) Servers/daemons usually use well-known ports any client can identify the server/service (HTTP = 80, FTP = 21, Telnet = 23,...) Clients usually use dynamic ports assigned by the kernel at run time
IP Specific Generic struct sockaddr { unsigned short sa_family; /* Address family (e.g., AF_INET) */ char sa_data[14]; /* Protocol-specific address information */ }; struct sockaddr_in { unsigned short sin_family; /* Internet protocol (AF_INET) */ unsigned short sin_port; /* Port (16-bits) */ struct in_addr sin_addr; /* Internet address (32-bits) */ char sin_zero[8]; /* Not used */ }; struct in_addr { unsigned long s_addr; /* Internet address (32-bits) */ }; sockaddr Family Blob 2 bytes 2 bytes 4 bytes 8 bytes sockaddr_in Family Port Internet address Not used
Assigning an addr. to a socket The bind() is used to assign an address to an created socket. int bind( int sockfd, struct sockaddr *localaddr, int addrlen); bind returns 0 if successful or -1 on error.
bind() Example int mysock,err; struct sockaddr_in myaddr; char* servip; /* ex)203.252.164.143 */ mysock = socket(pf_inet,sock_stream,0); myaddr.sin_family = AF_INET; myaddr.sin_port = htons( portnum ); myaddr.sin_addr.s_addr = inet_addr(servip); err=bind(mysock, (sockaddr *) &myaddr, sizeof(myaddr));
Socket Flow (UDP)
Client-Server communication Client must contact server server process must first be running server must have created socket that accepts client s contact Client contacts server by creating client-local TCP socket specifying IP address, port number of server process
Socket Flow (TCP)
Server side - listen() Used by connection-oriented servers to indicate an application is willing to receive connections int listen(int socket, int queuelimit) Socket: handle of newly created socket Only 1 for server queuelimit: number of connection requests that can be queued by the system while waiting for server to execute accept call.
Server side - Accept() int accept(int socket, struct sockaddr *clientdaddress, int addr_len) After listen(), the accept() carries out a passive open Create socket for the client tries connect() Returns a new socket can send(receive) data to(from) client
Client Side - Connect() int connect(int socket, struct sockaddr *foreignaddress, int addr_len) Client executes an active open of a connection send syn, 3way handshake When success, socket desc is filled with address infos. Client OS usually selects random, unused port foreignaddress field contains remote system s address
Close() int close(int socket) Delete socket descriptor In case of TCP, send fin
Send(to), Recv(from) Once a connection has been made, application can send/recv data int send(int socket, char *message, int msg_len, int flags) Send specified message using specified socket int recv(int scoket, char *buffer, int buf_len, int flags) Receive message from specified socket into specified buffer
System View
Socket Flow(revisit) Server Socket() Bind() Block until connect Process request Listen() Accept() Recv() Send() Connection Establishmt. Data (request) Data (reply) Client Socket() Connect() Send() Recv()
Clients and Servers Client: Initiates the connection Client: Bob Server: Jane Hi. I m Bob. Nice to meet you, Jane. Hi, Bob. I m Jane Server: Passively waits to respond
TCP Client/Server Interaction Server starts by getting ready to receive client connections Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Assign a port to socket 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction /* Create socket for incoming connections */ if ((servsock = socket(pf_inet, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed"); Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction echoservaddr.sin_family = AF_INET; /* Internet address family */ echoservaddr.sin_addr.s_addr = htonl(inaddr_any);/* Any incoming interface */ echoservaddr.sin_port = htons(echoservport); /* Local port */ if (bind(servsock, (struct sockaddr *) &echoservaddr, sizeof(echoservaddr)) < 0) DieWithError("bind() failed"); Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction /* Mark the socket so it will listen for incoming connections */ if (listen(servsock, MAXPENDING) < 0) DieWithError("listen() failed"); Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction for (;;) /* Run forever */ { clntlen = sizeof(echoclntaddr); if ((clntsock=accept(servsock,(struct sockaddr *)&echoclntaddr,&clntlen)) < 0) DieWithError("accept() failed"); Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction Server is now blocked waiting for connection from a client Later, a client decides to talk to the server Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction /* Create a reliable, stream socket using TCP */ if ((sock = socket(pf_inet, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed"); Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction echoservaddr.sin_family = AF_INET; /* Internet address family */ echoservaddr.sin_addr.s_addr = inet_addr(servip); /* Server IP address */ echoservaddr.sin_port = htons(echoservport); /* Server port */ if (connect(sock, (struct sockaddr *) &echoservaddr, sizeof(echoservaddr)) < 0) DieWithError("connect() failed"); Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction if ((clntsock=accept(servsock,(struct sockaddr *)&echoclntaddr,&clntlen)) < 0) DieWithError("accept() failed"); Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction echostringlen = strlen(echostring); /* Determine input length */ /* Send the string to the server */ if (send(sock, echostring, echostringlen, 0)!= echostringlen) DieWithError("send() sent a different number of bytes than expected"); Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction /* Receive message from client */ if ((recvmsgsize = recv(clntsocket, echobuffer, RCVBUFSIZE, 0)) < 0) DieWithError("recv() failed"); Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCP Client/Server Interaction close(sock); close(clntsocket) Client 1. Create a TCP socket 2. Establish connection 3. Communicate 4. Close the connection Server 1. Create a TCP socket 2. Bind socket to a port 3. Set socket to listen 4. Repeatedly: a. Accept new connection b. Communicate c. Close the connection
TCPEchoClient.c(1/3) #include <stdio.h> /* for printf() and fprintf() */ #include <sys/socket.h> /* for socket(), connect(), send(), and recv() */ #include <arpa/inet.h> /* for sockaddr_in and inet_addr() */ #include <stdlib.h> /* for atoi() and exit() */ #include <string.h> /* for memset() */ #include <unistd.h> /* for close() */ #define RCVBUFSIZE 32 /* Size of receive buffer */ void DieWithError(char *errormessage); /* Error handling function */ int main(int argc, char *argv[]) { int sock; /* Socket descriptor */ struct sockaddr_in echoservaddr; /* Echo server address */ unsigned short echoservport; /* Echo server port */ char *servip; /* Server IP address (dotted quad) */ char *echostring; /* String to send to echo server */ char echobuffer[rcvbufsize]; /* Buffer for echo string */ unsigned int echostringlen; /* Length of string to echo */ int bytesrcvd, totalbytesrcvd; /* Bytes read in single recv() and total bytes read */
TCPEchoClient.c(2/3) if ((argc < 3) (argc > 4)){ /* Test for correct number of arguments */ fprintf(stderr, "Usage: %s <Server IP> <Echo Word> [<Echo Port>]\n", argv[0]); exit(1); } servip = argv[1]; /* First arg: server IP address (dotted quad) */ echostring = argv[2]; /* Second arg: string to echo */ if (argc == 4) echoservport = atoi(argv[3]); /* Use given port, if any */ else echoservport = 7; /* 7 is the well-known port for the echo service */ /* Create a reliable, stream socket using TCP */ if ((sock = socket(pf_inet, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed"); /* Construct the server address structure */ memset(&echoservaddr, 0, sizeof(echoservaddr)); /* Zero out structure */ echoservaddr.sin_family = AF_INET; /* Internet address family */ echoservaddr.sin_addr.s_addr = inet_addr(servip); /* Server IP address */ echoservaddr.sin_port = htons(echoservport); /* Server port */
TCPEchoClient.c(3/3) /* Establish the connection to the echo server */ if (connect(sock, (struct sockaddr *) &echoservaddr, sizeof(echoservaddr)) < 0) DieWithError("connect() failed"); echostringlen = strlen(echostring); /* Determine input length */ /* Send the string to the server */ if (send(sock, echostring, echostringlen, 0)!= echostringlen) DieWithError("send() sent a different number of bytes than expected"); /* Receive the same string back from the server */ totalbytesrcvd = 0; printf("received: "); /* Setup to print the echoed string */ while (totalbytesrcvd < echostringlen) { /* Receive up to the buffer size (minus 1 to leave space for a null terminator) bytes from the sender */ if ((bytesrcvd = recv(sock, echobuffer, RCVBUFSIZE - 1, 0)) <= 0) DieWithError("recv() failed or connection closed prematurely"); totalbytesrcvd += bytesrcvd; /* Keep tally of total bytes */ echobuffer[bytesrcvd] = '\0'; /* Terminate the string! */ printf(echobuffer); /* Print the echo buffer */ } printf("\n"); /* Print a final linefeed */ close(sock); exit(0);
TCPEchoServer.c(1/3) /*... Header Same with client!! */ #define MAXPENDING 5 /* Maximum outstanding connection requests */ void DieWithError(char *errormessage); /* Error handling function */ void HandleTCPClient(int clntsocket); /* TCP client handling function */ int main(int argc, char *argv[]) { int servsock; /* Socket descriptor for server */ int clntsock; /* Socket descriptor for client */ struct sockaddr_in echoservaddr; /* Local address */ struct sockaddr_in echoclntaddr; /* Client address */ unsigned short echoservport; /* Server port */ unsigned int clntlen; /* Length of client address data structure */ if (argc!= 2) { /* Test for correct number of arguments */ fprintf(stderr, "Usage: %s <Server Port>\n", argv[0]); exit(1); }
TCPEchoServer.c(2/3) echoservport = atoi(argv[1]); /* First arg: local port */ /* Create socket for incoming connections */ if ((servsock = socket(pf_inet, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed"); /* Construct local address structure */ memset(&echoservaddr, 0, sizeof(echoservaddr)); /* Zero out structure */ echoservaddr.sin_family = AF_INET; /* Internet address family */ echoservaddr.sin_addr.s_addr = htonl(inaddr_any); /* Any incoming interface */ echoservaddr.sin_port = htons(echoservport); /* Local port */ /* Bind to the local address */ if (bind(servsock, (struct sockaddr *) &echoservaddr, sizeof(echoservaddr)) < 0) DieWithError("bind() failed"); /* Mark the socket so it will listen for incoming connections */ if (listen(servsock, MAXPENDING) < 0) DieWithError("listen() failed");
TCPEchoServer.c(3/3) for (;;) /* Run forever */ { /* Set the size of the in-out parameter */ clntlen = sizeof(echoclntaddr); /* Wait for a client to connect */ if ((clntsock = accept(servsock, (struct sockaddr *) &echoclntaddr, &clntlen)) < 0) DieWithError("accept() failed"); /* clntsock is connected to a client! */ printf("handling client %s\n", inet_ntoa(echoclntaddr.sin_addr)); } } HandleTCPClient(clntSock); /* NOT REACHED */
HandleTCPClient.c #include <stdio.h> /* for printf() and fprintf() */ #include <sys/socket.h> /* for recv() and send() */ #include <unistd.h> /* for close() */ #define RCVBUFSIZE 32 /* Size of receive buffer */ void DieWithError(char *errormessage); /* Error handling function */ void HandleTCPClient(int clntsocket) { } char echobuffer[rcvbufsize]; /* Buffer for echo string */ int recvmsgsize; /* Size of received message */ /* Receive message from client */ if ((recvmsgsize = recv(clntsocket, echobuffer, RCVBUFSIZE, 0)) < 0) DieWithError("recv() failed"); /* Send received string and receive again until end of transmission */ while (recvmsgsize > 0) { /* zero indicates end of transmission */ /* Echo message back to client */ if (send(clntsocket, echobuffer, recvmsgsize, 0)!= recvmsgsize) DieWithError("send() failed"); /* See if there is more data to receive */ if ((recvmsgsize = recv(clntsocket, echobuffer, RCVBUFSIZE, 0)) < 0) DieWithError("recv() failed"); } close(clntsocket); /* Close client socket */
DieWithError.c #include <stdio.h> #include <stdlib.h> void DieWithError(char * errormessage) { perror(errrormessage); exit(1); }
Winsock #include <stdio.h> #include <winsock.h> #include <stdlib.h> void main() { WSADATA wsadata; } if (WSAStartup(MAKEWORD(2, 0), &wsadata)!= 0) { fprintf(stderr, "WSAStartup() failed"); exit(1); } closesocket(sock);
Winsock for visual studio, you must add wsock32.lib manually menu->project->settings->link->wsock32.lib */
Assignment #0 앞의 client 코드와 Server 코드를컴파일하여동작을확인하라 Linux 머싞혹은 windows 에서 cygwin 을설치하였을경우동작한다. www.cygwin.com 필수설치패키지 gcc 패키지 Client Part TcpEchoClient.c, DieWithError.c Server Part TcpEchoServer.c, DieWithError.c, HandleTcpClient.c
Gcc 컴파일법 #gcc o client TcpEchoClient.c DieWithError.c Output binary filename Source files
Assignment #1 기본과제 앞의예제를수정하여다음의기능을가지는프로그램을작성하라 서버는클라이언트의문자열을화면에출력한다. 서버는클라이언트의문자열을동시에파일로저장한다. 파일이름은 echo_history.log 이며 append 로계속추가되게한다.
Assignment #1.5 순차적채팅프로그램작성 Assignment #0 혹은 #1 을수정하여다음의조건을만족하는프로그램을작성한다. 클라이언트는표준입력으로받은문자열을서버로젂송 명령어행인자가아닌프로그램실행중입력받음 서버는받을문자열을출력하고사용자로부터표준입력으로문자열을받아클라이언트로젂송 클라이언트는받은문자열을출력하고위를반복 서버와클라이언트는상대방문자열출력시앞에상대방의 IP 를표기할것, 형식은자유 ex) From 192.168.0.1 : Hello!!! /quit 를입력시프로그램종료