440 likes | 458 Views
Network Programming Week #1. J.P. Yoo willow@konkuk.ac.kr. TCP/IP Sockets in C: Practical Guide for Programmers. Michael J. Donahoo Kenneth L. Calvert. Network API. Interface between application and protocol software. Application. Network API. Protocol A. Protocol B. Protocol C.
E N D
Network Programming Week #1 J.P. Yoo willow@konkuk.ac.kr
TCP/IP Sockets in C: Practical Guide for Programmers Michael J. Donahoo Kenneth L. Calvert
Network API • Interface between application and protocol software. Application Network API Protocol A Protocol B Protocol C
Socket • Programming Interface between application and network • Network API sets for TCP/IP protocol suite • A socket is an abstract representation of a communication endpoint. • Sockets work with Unix I/O services just like files, pipes & FIFOs. • Difference • establishing a connection • specifying communication endpoint addresses
Unix Descriptor Table Descriptor Table Data structure for file 0 0 1 Data structure for file 1 2 3 Data structure for file 2 4
Socket Descriptor Structure Descriptor Table Family: PF_INET Service: SOCK_STREAM Local IP: 111.22.3.4 Remote IP: 123.45.6.78 Local Port: 2249 Remote Port: 3726 0 1 2 3 4
Sockets • Identified by protocol and local/remote address/port • Applications may refer to many sockets • Sockets accessed by many applications
Creating a Socket int socket(int family,int type,int proto); • create a resource for communication endpoint • socket call does not specify where data will be coming from, nor where it will be going to – it just creates the interface! • Socket reference • File (socket) descriptor in UNIX • Socket handle in WinSock
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 Two essential types of sockets • SOCK_STREAM • a.k.a. TCP • reliable delivery • in-order guaranteed • connection-oriented • bidirectional
Data I/O 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?
Specifying an Endpoint Addr. • 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
TCP/IP Addresses • We don’t need to deal with sockaddr structures since we will only deal with a real protocol family(TCP/IP). • We can use sockaddr_instructures.
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) */ }; IP Specific sockaddr Family Blob 8 bytes 2 bytes 4 bytes 2 bytes Family Port Not used sockaddr_in Internet address
Assigning an addr. to a socket • The bind() system call is used to assign an address to an existing socket. • bind returns 0 if successful or -1 on error. int bind( int sockfd, struct sockaddr *localaddr, int addrlen);
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 Server Socket() Bind() Client Listen() Socket() Accept() Connection Establishmt. Connect() Block until connect Data (request) Send() Recv() Process request Data (reply) Send() Recv()
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 creates 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.
Accept() int accept(int socket, struct sockaddr *clientdaddress, int addr_len) • After executing listen, the accept() carries out a passive open • Create socket for the client which is doing connect() • it returns with a new socket that corresponds with new connection and the address contains the clients address
Connect() int connect(int socket, struct sockaddr *address, int addr_len) • Client executes an active open of a connection • Address field contains remote system’s address • Client OS usually selects random, unused port
Send(to), Recv(from) • After connection has been made, application uses send/recv to 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
Socket Flow(revisit) Server Socket() Bind() Client Listen() Socket() Accept() Connection Establishmt. Connect() Block until connect Data (request) Send() Recv() Process request Data (reply) Send() Recv()
Clients and Servers • Client: Initiates the connection • Server: Passively waits to respond Server: Jane Client: Bob “Hi, Bob. I’m Jane” “Hi. I’m Bob.” “Nice to meet you, Jane.”
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Assign a port to socket Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server Interaction Server starts by getting ready to receive client connections…
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate 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 Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate 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 Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate 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 Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate 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 Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate 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 Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate 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 Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate 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 Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server Interaction if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen)) < 0) DieWithError("accept() failed");
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate 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 Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server Interaction /* Receive message from client */ if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0) DieWithError("recv() failed");
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server Interaction close(sock); close(clntSocket)
#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 */ 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(1/2)
/* 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); TCPEchoClient.c(2/2)
#include <stdio.h> /* for printf() and fprintf() */ #include <sys/socket.h> /* for socket(), bind(), and connect() */ #include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */ #include <stdlib.h> /* for atoi() and exit() */ #include <string.h> /* for memset() */ #include <unistd.h> /* for close() */ #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(1/2) 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");
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 */ } TCPEchoServer.c(2/2)
#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"); HandleTCPClient.c /* 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 */ }
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로 계속 추가되게 한다. • Challenge • 파일의 소유권, permission등도 유지가되도록하라.