前言
本章节是用基本的Linux/Unix基本函数编写一个完整的服务器和客户端例子,可在Linux(ubuntu)和Unix(freebsd)上运行,客户端和服务端的功能如下:
客户端从标准输入读入一行,发送到服务端
服务端从网络读取一行,然后输出到客户端
客户端收到服务端的响应,输出这一行到标准输出
服务端
代码如下:
#include <unistd.h> #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <arpa/inet.h> /* inet(3) functions */ #include <stdlib.h> #include <errno.h> #include <stdio.h> #include <string.h> #define MAXLINE 1024 //typedef struct sockaddr SA; void handle(int connfd); int main(int argc, char **argv) { int listenfd, connfd; int serverPort = 6888; int listenq = 1024; pid_t childpid; char buf[MAXLINE]; socklen_t socklen; struct sockaddr_in cliaddr, servaddr; socklen = sizeof(cliaddr); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(serverPort); listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd < 0) { perror("socket error"); return -1; } if (bind(listenfd, (struct sockaddr *) &servaddr, socklen) < 0) { perror("bind error"); return -1; } if (listen(listenfd, listenq) < 0) { perror("listen error"); return -1; } printf("echo server startup,listen on port:%d\n", serverPort); for ( ; ; ) { connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &socklen); if (connfd < 0) { perror("accept error"); continue; } sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port); printf(buf,""); childpid = fork(); if (childpid == 0) { /* child process */ close(listenfd); /* close listening socket */ handle(connfd); /* process the request */ exit (0); } else if (childpid > 0) { close(connfd); /* parent closes connected socket */ } else { perror("fork error"); } } } void handle(int connfd) { size_t n; char buf[MAXLINE]; for(;;) { n = read(connfd, buf, MAXLINE); if (n < 0) { if(errno != EINTR) { perror("read error"); break; } } if (n == 0) { //connfd is closed by client close(connfd); printf("client exit\n"); break; } //client exit if (strncmp("exit", buf, 4) == 0) { close(connfd); printf("client exit\n"); break; } write(connfd, buf, n); //write maybe fail,here don't process failed error } }
客户端
代码如下:
#include <unistd.h> #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <arpa/inet.h> /* inet(3) functions */ #include <netdb.h> /*gethostbyname function */ #include <stdlib.h> #include <errno.h> #include <stdio.h> #include <string.h> #define MAXLINE 1024 void handle(int connfd); int main(int argc, char **argv) { char * servInetAddr = "127.0.0.1"; int servPort = 6888; char buf[MAXLINE]; int connfd; struct sockaddr_in servaddr; if (argc == 2) { servInetAddr = argv[1]; } if (argc == 3) { servInetAddr = argv[1]; servPort = atoi(argv[2]); } if (argc > 3) { printf("usage: echoclient <IPaddress> <Port>\n"); return -1; } connfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(servPort); inet_pton(AF_INET, servInetAddr, &servaddr.sin_addr); if (connect(connfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { perror("connect error"); return -1; } printf("welcome to echoclient\n"); handle(connfd); /* do it all */ close(connfd); printf("exit\n"); exit(0); } void handle(int sockfd) { char sendline[MAXLINE], recvline[MAXLINE]; int n; for (;;) { if (fgets(sendline, MAXLINE, stdin) == NULL) { break;//read eof } /* //也可以不用标准库的缓冲流,直接使用系统函数无缓存操作 if (read(STDIN_FILENO, sendline, MAXLINE) == 0) { break;//read eof } */ n = write(sockfd, sendline, strlen(sendline)); n = read(sockfd, recvline, MAXLINE); if (n == 0) { printf("echoclient: server terminated prematurely\n"); break; } write(STDOUT_FILENO, recvline, n); //如果用标准库的缓存流输出有时会出现问题 //fputs(recvline, stdout); } }
编译和启动服务器:
gcc echoserver.c -o echoserver ./echoserver
编译和启动客户端
gcc echoclient.c -o echoclient ./echoclient