Penguin
Diff: NetworkProgramming
EditPageHistoryDiffInfoLikePages

Differences between version 10 and previous revision of NetworkProgramming.

Other diffs: Previous Major Revision, Previous Author, or view the Annotated Edit History

Newer page: version 10 Last edited on Saturday, July 27, 2002 4:38:55 pm by PerryLorier Revert
Older page: version 1 Last edited on Wednesday, July 24, 2002 4:22:36 pm by PerryLorier Revert
@@ -1,128 +1,106 @@
-This is to describe how to write networking programs in [C] using the [BSD] Socket Layer [API]. This mostly applies to almost all other languages with only minor modifications. 
+This is to describe how to write networking programs in [C] using the [BSD] Socket Layer [API]. This mostly applies to almost all other languages with only minor modifications. This is an updated version of the page which is designed to be non-AddressFamily specific, for the old version see NetworkProgrammingOld  
  
-!!!How to create a [TCP] Server  
-;1 :[TCP] is a streaming socket from the internet family of protocols, so first we create a socket of the correct type:  
- struct protoent *protocol;  
- int serverfd;  
+!!!General structure for a server setup  
+The various steps of setting up a server are :  
+# Creating a socket of the correct type, with socket(2)  
+# bind(2) the socket to a port (and optionally an interface)  
+# listen(2) on that port  
+# accept(2) client connections  
  
- protocol=getprotobyname ("tcp" );  
- if (!protocol ) {  
- printf ("Could not getprotobyname" );  
- !exit(1);  
- }  
- server=socket(PF_INET ,SOCK_STREAM,protocol .p_proto);  
- if (server<) {  
- perror("socket");  
- !exit(2);  
- }  
+getaddrinfo (3 ) will sort out the correct parameters for socket (2 ) and bind (2 ), making things fairly simple . An example below:  
  
-;2: Then we create an address to bind it to. We don't care which of our local IP's we bind it to so we choose "INADDR_ANY" (all interfaces)  
- struct sockaddr_in address;  
- address .sin_family = AF_INET;  
- address .sin_port = htons(''port goes here'')  
- address.sin_addr .s_addr = INADDR_ANY;  
+* First find our what to bind to.  
+ #include <sys/socket .h>  
+ #include <sys/types .h>  
+ #include <netdb .h>  
  
-;3: Then we bind the port to that socket.  
- if (bind(serverfd ,&address,sizeof(address))< ) {  
- perror("bind") ;  
- !exit(3) ;  
- }  
+ int bind_service (char *service ,int socktype ) {  
+ struct addrinfo hints ;  
+ struct addrinfo *result ;  
+ struct addrinfo *result_iter;  
+ int serverfd;  
  
-;4: Now we start listening on that port . The 5 is the number of outstanding connections that will be queued by the kernel before you get a chance to accept(2) them .  
- if (listen(serverfd ,5)< ) {  
- perror ("listen" );  
- !exit(4) ;  
- }  
+ hints .ai_flags=AI_PASSIVE;  
+ hints .ai_family=PF_UNSPEC; /* We don't care if it's PF_INET , or PF_INET6 */  
+ hints.ai_socktype=SOCK_STREAM /* 0 for any type, SOCK_STREAM for streams, SOCK_DGRAM for datagrams */  
+ hints.ai_protocol=; /* 0 for any protocol, use getprotobyname (3 ) to find a protocol */  
+ hints.ai_addrlen= ;  
+ hints.ai_addr=NULL ;  
+ hints.ai_canonname=NULL; /* Unused */  
+ hints.ai_next=NULL;  
  
-;5: And now we wait for an incoming connection  
- int sockfd;  
- struct sockaddr _in clientaddress
+ ret=getaddrinfo(NULL,service,&hints,&result) ;  
+ if (ret!=) {  
+ fprintf(stderr,"getaddrinfo failed: %s",gai _strerror(ret)) ;  
+ return -1;  
+ }  
  
- sockfd=accept (serverfd,&clientaddress ,sizeof (clientaddress )); 
+ for (result_iter = result;result_iter;result_iter=result_iter->next) {  
+ serverfd = socket(result_iter->ai_family ,result_iter->ai_socktype ,result_iter->ai_protocol);  
+ if (serverfd< ) {  
+ perror("socket" );  
+ continue;  
+ }  
+ if (bind(serverfd,result_iter->address,result_iter->addrlen)<) {  
+ perror("bind");  
+ continue;  
+ }  
+ break;  
+ }  
  
- if (sockfd< ) {  
- perror ("accept ");  
- !exit (5 ); 
+ if (!result_iter ) {  
+ fprintf (stderr, "Unable to bind to service \ "%s\"\n",service );  
+ freeaddrinfo (result );  
+ return -1;  
+ }  
+  
+ freeaddrinfo(result);  
+ return serverfd
 
  
-This creates a new socket (called "sockfd ") that we can talk to the client that connected with. We can go back and do the accept (2 ) again to get another client socket etc.  
+ void do_client (int clientfd)  
+ {  
+ char *message = "Hello World\n ";  
+ write(clientfd,message );  
+ close (clientfd );  
+ }  
  
-!!!How to create a [TCP] Client  
-;1: First you need to create a socket as in TCP Server step 1 above , note the rest of this example uses "sockfd" not " serverfd"  
+ int main(int argc ,char **argv)  
+ {  
+ int serverfd;  
  
-;2: Optionally you can bind the socket to a local address using step 2 and 3 above. Note , this isn't necessary, or usually even desired.  
+ serverfd = bind_service("hello" ,SOCK_STREAM);  
  
-;3: Next you want to create an address to connect out to:  
- struct sockaddr_in address
+ if (serverfd<) {  
+ return 1 ;  
+ }  
  
- address.sin_family = AF_INET;  
- address.sin_port = htons (''port goes here'' );  
-  
- struct hostent *host;  
- int i= ;  
- int success=;  
- host = gethostbyname("''host.name.goes.here''");  
- if (!host ) {  
- fprintf (stderr, "gethostbyname: %s ",hstrerror(herrno) );  
- !exit(5);  
- }  
- for (i=;i<host->h_length;i++) {  
- if(connect(sockfd,&address,sizeof(address))==) {  
- success= 1;  
- break
+ if (listen (serverfd,8 )< ) {  
+ perror ("listen ");  
+ return 1; 
 
- fprintf(stderr,"connect(%s):%s",inet_ntoa(address.sin_addr),strerror(errno));  
- }  
- if (!success) {  
- fprintf(stderr,"hostname is unreachable");  
- !exit(6);  
- }  
  
-Done!  
+ for (;;) {  
+ int clientfd;  
  
-!!!How to talk over a [TCP] socket.  
-Now, after you have [TCP] connection, either by having accept(2 ) or connect(2) return, you want to send traffic over it.  
+ clientfd = accept(serverfd );  
  
-!!To Read Data:  
- char buffer[[65535];  
- int bytes;  
- bytes=read(sockfd,buffer,sizeof(buffer));  
- if (bytes <) {  
- perror("read ");  
- }  
- else if (bytes==) {  
- close(sockfd);  
- printf("Socket closed");  
- exit();  
- }  
- ''process data''  
+ if (clientfd <) {  
+ perror("accept ");  
+ /* Note that accept tends to fail reasonably often, so don't abort the server here */  
+
  
-The number of bytes read is in "bytes", if bytes is , then the other end closed the connection.  
+ if (fork()== ) {  
+ /* Client Thread */  
+ close(serverfd);  
+ do_client(clientfd);  
+ exit();  
+ }  
+ else {  
+ /* Server Thread */  
+ close(clientfd);  
+ }  
+ }  
  
-!!To Write Data  
- char buffer[[65535];  
- int bytes;  
- int remaining;  
- ''populate buffer with data, set bytes to being the number of bytes to write, eg:  
- strcpy(buffer,"Hello World");  
- bytes=strlen(buffer); ''  
- remaining=bytes;  
- while(remaining>) {  
- ret=write(sockfd,buffer+(bytes-remaining),remaining);  
- if (ret<) {  
- perror("write");  
- close(ret);  
- !exit(8 );  
- }  
- remaining=remaining-ret
+ close(serverfd ); 
 
-  
-  
-!!!How to write a [UDP] Server  
-(To be written)  
-  
-!!!How to write a [UDP] Client  
-(To be written)  
-  
-!!!Differences between [TCP]/[UDP] (ip(7)) and Unix Domain Sockets (unix(7))  
-(To be written)