Sie sind auf Seite 1von 12

Introduction to the Socket API

Tom Kelliher, CS43 ,Mar. 19, 1996 A Client-Server Dialogue

Sockets API
socket()
#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol);

Used to create an unamed socket. Must bind or connect. Returns a socket descriptor (small positive int). Returns -1 on error.
domain: type:

--- UNIX domain protocols. AF_INET --- Internet domain protocols. ...
AF_UNIX

--- TCP protocol. SOCK_DGRAM --- UDP protocol. SOCK_RAW --- IP protocol. ...
SOCK_STREAM

protocol:

set to 0.

Typical call:
int sock; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) die();

bind()
#include <sys/types.h> #include <sys/socket.h> int bind(int sd, const struct sockaddr *name, int namelen);

Assigns a name (port, etc.) to a socket.

Returns 0 if successful, otherwise -1 and look in errno.


sd:

socket descriptor.

name:

Pointer to a struct sockaddr_in for Internet sockets. Cast to struct sockaddr *.


/* * Socket address, internet style. */ struct sockaddr_in { u_char sin_len; u_char sin_family; /* AF_INET */ u_short sin_port; /* 16 bit port number */ struct in_addr sin_addr; /* IP address */ char sin_zero[8]; };

For a server:
o o

--- desired listen port. Gt 5000. sin_addr --- another struct. Where we're willing to accept connections from.
sin_port

namelen:

sizeof name structure.

Typical call:
struct sockaddr_in server; bzero((char *) &server, sizeof(server)); server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(SERVER_PORT); if (bind(sock, (struct sockaddr *) &server, sizeof(server))) die();

listen()
#include <sys/types.h> #include <sys/socket.h> int listen(int sd, int backlog);

Announce willingness to accept connections to socket and a maximum queue length. Returns 0 on success, otherwise -1.

sd:

socket descriptor. max size of queue. Maximum is 5.

backlog:

Typical call:
int sock; listen(sock, 5);

accept()
#include <sys/types.h> #include <sys/socket.h> int accept(int sd, struct sockaddr *addr, int *addrlen);

Extract first connection request on queue; blocking if queue is empty. Returns -1 on error, otherwise a non-negative descriptor to use for socket I/O ( read() or write()).
sd:

socket descriptor.

addr:

Pointer to a struct sockaddr_in for Internet sockets. Cast to struct sockaddr *. sin_port --- client port. sin_addr --- client IP address. addressof sizeof addr structure.

addrlen:

Typical call:
struct sockaddr_in client; int msgsock, sock, clientLen; clientLen = sizeof(client); if ((msgsock = accept(sock, (struct sockaddr *) &client, &clientLen)) == -1) die(); else { /* Print information about the client. */ if (clientLen != sizeof(client)) die(); printf("Client IP: %s\n", inet_ntoa(client.sin_addr));

printf("Client Port: %hu\n", ntohs(client.sin_port));

connect()
#include <sys/types.h> #include <sys/socket.h> int connect(int sd, const struct sockaddr *name, int namelen);

Connect socket to another socket, opening a socket pair communication channel. Returns 0 on success, -1 otherwise. Check errno.
sd:

socket descriptor.

name:

Pointer to a struct sockaddr_in for Internet sockets. Cast to struct sockaddr *. sin_port --- server port. sin_addr --- server IP address. sizeof name structure.

namelen:

Will automatically do a bind and assign an ephemeral port. Use getsockname() to discover the port number. Typical call:
struct sockaddr_in server; struct hostent* hp; bzero((char *) &server, sizeof(server)); server.sin_family = AF_INET; if ((hp = gethostbyname(argv[1])) == NULL) { sprintf(buf, "%s: unknown host\n", argv[1]); die(buf); } bcopy(hp->h_addr, &server.sin_addr, hp->h_length); server.sin_port = htons((u_short) SERVER_PORT); /* Try to connect */ if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) pdie("Connecting stream socket"); /* Determine what port client's using. */ clientLen = sizeof(client); if (getsockname(sock, (struct sockaddr *) &client, &clientLen)) pdie("Getting socket name");

if (clientLen != sizeof(client)) die("getsockname() overwrote name structure"); printf("Client socket has port %hu\n", ntohs(client.sin_port));

read()
#include <unistd.h> ssize_t read(int sd, void* buf, size_t nbytes);

Read at most nbytes bytes into buf from sd. Returns -1 on error, 0 on EOF (connection closed), or the actual number of bytes read.
sd:

socket descriptor. addressof char buffer. sizeof buf.

buf:

nbytes:

Typical call:
char buf[BUFFER_SIZE]; int rval, msgsock; bzero(buf, BUFFER_SIZE); if ((rval = read(msgsock, buf, BUFFER_SIZE)) < 0) die();

write()
#include <unistd.h> ssize_t write(int sd, const void *buf, size_t nbytes);

Attempts to write nbytes from buf to sd. Returns -1 on error or the number of bytes actually written. Arguments similar to read().

close()
#include <unistd.h>

int close(int sd);

Close socket descriptor sd. Returns -1 on failure, otherwise 0.

Byte Ordering Calls


#include <sys/param.h> u_long u_short u_long u_short htonl(u_long hostlong); htons(u_short hostshort); ntohl(u_long netlong); ntohs(u_short netshort);

Convert 16- and 32-bit integers between native format (host) and network format.
#include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> unsigned long inet_addr(const char *ip); char* inet_ntoa(struct in_addr in); inet_addr()

converts a char string IP address to its 32-bit network byte-order integer

equivalent.
inet_ntoa

does the opposite.

Example Server Program


/********************************************************************** * server.c --- Demonstrate a simple iterative server. * Tom Kelliher * * This program demonstrates a simple iterative server. The server * opens a TCP connection on port SERVER_PORT and begins accepting * connections from anywhere. It sits in an endless loop, so one must * send an INTR to terminate it. * * The server reads a message from the client, printing it to stdout. * Then, the server sends a simple message back to the client. **********************************************************************/ #include #include #include #include #include <sys/types.h> <sys/socket.h> <netinet/in.h> <netdb.h> <stdio.h>

#include <stdlib.h> #define #define #define #define DATA "Danger Will Roger . . ." TRUE 1 SERVER_PORT 5001 BUFFER_SIZE 1024

/* prototypes */ void die(const char *); void pdie(const char *); /********************************************************************** * main **********************************************************************/ int main(void) { int sock; /* fd for main socket */ int msgsock; /* fd from accept return */ struct sockaddr_in server; /* socket struct for server connection */ struct sockaddr_in client; /* socket struct for client connection */ int clientLen; /* returned length of client from accept() */ int rval; /* return value from read() */ char buf[BUFFER_SIZE]; /* receive buffer */ /* Open a socket, not bound yet. Type is Internet TCP. */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) pdie("Opening stream socket"); /* Prepare to bind. Permit Internet connections from any client to our SERVER_PORT. */ bzero((char *) &server, sizeof(server)); server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(SERVER_PORT); if (bind(sock, (struct sockaddr *) &server, sizeof(server))) pdie("Binding stream socket"); printf("Socket has port %hu\n", ntohs(server.sin_port)); /* Set the listen queue to 5, the maximum. */ listen(sock, 5); /* Loop, waiting for client connections. */ /* This is an interactive server. */ while (TRUE) { clientLen = sizeof(client); if ((msgsock = accept(sock, (struct sockaddr *) &client, &clientLen)) == -1) pdie("Accept"); else {

/* Print information about the client. */ if (clientLen != sizeof(client)) pdie("Accept overwrote sockaddr structure."); printf("Client IP: %s\n", inet_ntoa(client.sin_addr)); printf("Client Port: %hu\n", ntohs(client.sin_port)); do { /* Read from client until it's closed the connection. */ /* Prepare read buffer and read. */ bzero(buf, sizeof(buf)); if ((rval = read(msgsock, buf, BUFFER_SIZE)) < 0) pdie("Reading stream message"); if (rval == 0) /* Client has closed the connection */ fprintf(stderr, "Ending connection\n"); else printf("S: %s\n", buf); /* Write back to client. */ if (write(msgsock, DATA, sizeof(DATA)) < 0) pdie("Writing on stream socket"); } } exit(0); } /********************************************************************** * pdie --- Call perror() to figure out what's going on and die. **********************************************************************/ void pdie(const char *mesg) { perror(mesg); exit(1); } /********************************************************************** * die --- Print a message and die. **********************************************************************/ void die(const char *mesg) { fputs(mesg, stderr); fputc('\n', stderr); exit(1); } } while (rval != 0); /* else */

close(msgsock);

Example Client Program


/********************************************************************** * client.c --- Demonstrate a simple client. * Tom Kelliher * * This program will connect to a simple iterative server and exchange * messages. The single command line argument is the server's hostname. * The server is expected to be accepting connection requests from * SERVER_PORT. * * The same message is sent three times over separate connections, * demonstrating that different ephemeral ports are used for each * connection. **********************************************************************/ #include #include #include #include #include #include <sys/types.h> <sys/socket.h> <netinet/in.h> <netdb.h> <stdio.h> <stdlib.h>

#define DATA "The sea is calm tonight, the tide is full . . ." #define SERVER_PORT 5001 #define BUFFER_SIZE 1024 /* prototypes */ void die(const char *); void pdie(const char *); /********************************************************************** * main **********************************************************************/ int main(int argc, char *argv[]) { int sock; /* fd for socket connection */ struct sockaddr_in server; /* Socket info. for server */ struct sockaddr_in client; /* Socket info. about us */ int clientLen; /* Length of client socket struct. */ struct hostent *hp; /* Return value from gethostbyname() */ char buf[BUFFER_SIZE]; /* Received data buffer */ int i; /* loop counter */ if (argc != 2) die("Usage: client hostname"); /* Open 3 sockets and send same message each time. */ for (i = 0; i < 3; ++i)

{ /* Open a socket --- not bound yet. */ /* Internet TCP type. */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) pdie("Opening stream socket"); /* Prepare to connect to server. */ bzero((char *) &server, sizeof(server)); server.sin_family = AF_INET; if ((hp = gethostbyname(argv[1])) == NULL) { sprintf(buf, "%s: unknown host\n", argv[1]); die(buf); } bcopy(hp->h_addr, &server.sin_addr, hp->h_length); server.sin_port = htons((u_short) SERVER_PORT); /* Try to connect */ if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) pdie("Connecting stream socket"); /* Determine what port client's using. */ clientLen = sizeof(client); if (getsockname(sock, (struct sockaddr *) &client, &clientLen)) pdie("Getting socket name"); if (clientLen != sizeof(client)) die("getsockname() overwrote name structure"); printf("Client socket has port %hu\n", ntohs(client.sin_port)); /* Write out message. */ if (write(sock, DATA, sizeof(DATA)) < 0) pdie("Writing on stream socket"); /* Prepare our buffer for a read and then read. */ bzero(buf, sizeof(buf)); if (read(sock, buf, BUFFER_SIZE) < 0) pdie("Reading stream message"); printf("C: %s\n", buf); /* Close this connection. */ close(sock); } exit(0); } /********************************************************************** * pdie --- Call perror() to figure out what's going on and die. **********************************************************************/ void pdie(const char *mesg) { perror(mesg);

exit(1); } /********************************************************************** * die --- Print a message and die. **********************************************************************/ void die(const char *mesg) { fputs(mesg, stderr); fputc('\n', stderr); exit(1); }

Thomas P. Kelliher Mon Mar 18 22:35:52 EST 1996 Tom Kelliher

Das könnte Ihnen auch gefallen