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)