network programming week #1 j.p. yoo willow@konkuk.ac.kr

Post on 26-Mar-2015

222 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Network Programming Week #1

J.P. Yoowillow@konkuk.ac.kr

TCP/IP Sockets in C: Practical Guide for

Programmers

Michael J. DonahooKenneth L. Calvert

Network API

• Interface between application and protocol software.

ApplicationApplication

Network APINetwork API

Protocol AProtocol A Protocol BProtocol B Protocol CProtocol 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 TableDescriptor Table

0

1

2

3

4

Data structure for file 0Data structure for file 0

Data structure for file 1Data structure for file 1

Data structure for file 2Data structure for file 2

Socket Descriptor Structure

Descriptor TableDescriptor Table

0

1

2

3

4

Family: PF_INETFamily: PF_INETService: SOCK_STREAMService: SOCK_STREAMLocal IP: 111.22.3.4Local IP: 111.22.3.4Remote IP: 123.45.6.78Remote IP: 123.45.6.78Local Port: 2249Local Port: 2249Remote Port: 3726Remote Port: 3726

Family: PF_INETFamily: PF_INETService: SOCK_STREAMService: SOCK_STREAMLocal IP: 111.22.3.4Local IP: 111.22.3.4Remote IP: 123.45.6.78Remote IP: 123.45.6.78Local Port: 2249Local Port: 2249Remote Port: 3726Remote Port: 3726

Sockets

• Identified by protocol and local/remote address/port

• Applications may refer to many sockets• Sockets accessed by many applications

Creating a Socket

• 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

Family Type Protocol

TCPPF_INET

SOCK_STREAM IPPROTO_TCP

UDP SOCK_DGRAM IPPROTO_UDP

int socket(int family,int type,int proto);

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 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_in structures.

• 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) */};

Gen

eri

cIP

Speci

fic

sockaddr

sockaddr_in

Family

Family Port

Blob

Internet address Not used

2 bytes 2 bytes 4 bytes 8 bytes

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

Socket()Listen()

Accept()

Recv()

Send()

Connect()

Send()

Recv()

Block untilconnect

Processrequest

Connection Establishmt.

Data (request)

Data (reply)

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

• 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

Send(to), Recv(from)

Socket Flow(revisit)

Server

Socket()

Bind()

Client

Socket()Listen()

Accept()

Recv()

Send()

Connect()

Send()

Recv()

Block untilconnect

Processrequest

Connection Establishmt.

Data (request)

Data (reply)

• Client: Initiates the connection

• Server: Passively waits to respond

Clients and Servers

Client: Bob

“Hi. I’m Bob.”

“Nice to meet you, Jane.”

Server: Jane

“Hi, Bob. I’m Jane”

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Assign a port to socket3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

Server starts by getting ready to receive client connections…

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

/* Create socket for incoming connections */ if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed");

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

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");

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

/* Mark the socket so it will listen for incoming connections */ if (listen(servSock, MAXPENDING) < 0) DieWithError("listen() failed");

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

for (;;) /* Run forever */{ clntLen = sizeof(echoClntAddr);

if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen)) < 0) DieWithError("accept() failed");

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

Server is now blocked waiting for connection from a client

Later, a client decides to talk to the server…

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

/* Create a reliable, stream socket using TCP */ if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed");

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

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");

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen)) < 0) DieWithError("accept() failed");

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

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");

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

/* Receive message from client */ if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0) DieWithError("recv() failed");

TCP Client/Server Interaction

Client1. Create a TCP socket2. Establish connection3. Communicate4. Close the connection

Server1. Create a TCP socket2. Bind socket to a port3. Set socket to listen4. Repeatedly:

a. Accept new connectionb. Communicatec. Close the connection

close(sock); close(clntSocket)

TCPEchoClient.c(1/2)#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(2/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);

TCPEchoServer.c(1/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);

}

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(2/2)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 */

}

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 등도 유지가되도록하라 .

top related