Linux环境下服务器和客户端的网络通信

  UNIX系统中的网络协议是这样分层的:1.应用层(telnet,ftp等);2.主机到主机传输层(TCP,UDP);3.Internet层(IP和路由);4.网络访问层(网络,数据链路,物理层)。
  套接口描述符使用 sockaddr_in 数据结构,有了套接口之后需要调用bind()函数把套接口绑定到本地计算机的一个接口上,使用inet_addr()函数将普遍形式的IP地址转化为无符号的整型数,调用socket()函数获得文件描述符。程序分为客户端和服务端。应用select函数来实现异步的读写操作。在服务器端:首先先创建套接字,然后绑定,接下进入一个无限循环,用accept函数,接受“连接”请求,然后调用创建线程函数,创造新的线程,进入下一个循环。这样每当有一个新的“连接”被接受都会创建一个新的线程。

服务器端程序如下:

//server.c

View Code
  1 //server.c
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <errno.h>
  5 #include <string.h>
  6 #include <sys/types.h>
  7 #include <netinet/in.h>
  8 #include <sys/socket.h>
  9 #include <sys/wait.h>
 10 #include <unistd.h>
 11 #include <arpa/inet.h>
 12 #include <sys/time.h>
 13 #include <sys/types.h>
 14 
 15 #define MAXBUF 1024
 16 
 17 
 18 int main(int argc, char **argv)
 19 {
 20     int sockfd, new_fd;
 21     socklen_t len;
 22     struct sockaddr_in my_addr, their_addr;
 23     unsigned int myport, lisnum;
 24     char buf[MAXBUF + 1];
 25     fd_set rfds;
 26     struct timeval tv;
 27     int retval, maxfd = -1;
 28 
 29     if (argv[1])
 30         myport = atoi(argv[1]);
 31     else
 32         myport = 7838;
 33 
 34     if (argv[2])
 35         lisnum = atoi(argv[2]);
 36     else
 37         lisnum = 2;
 38 
 39     if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) 
 40    {
 41         perror("socket");
 42         exit(1);
 43     }
 44 
 45     bzero(&my_addr, sizeof(my_addr));
 46     my_addr.sin_family = PF_INET;
 47     my_addr.sin_port = htons(myport);
 48     if (argv[3])
 49         my_addr.sin_addr.s_addr = inet_addr(argv[3]);
 50     else
 51         my_addr.sin_addr.s_addr = INADDR_ANY;
 52 
 53     if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))
 54         == -1) {
 55         perror("bind");
 56         exit(1);
 57     }
 58 
 59     if (listen(sockfd, lisnum) == -1) {
 60         perror("listen");
 61         exit(1);
 62     }
 63 
 64     while (1) {
 65         printf
 66             (" ----等待新的连接到来开始新的聊天…… ");
 67         len = sizeof(struct sockaddr);
 68         if ((new_fd =
 69              accept(sockfd, (struct sockaddr *) &their_addr,
 70                     &len)) == -1) {
 71             perror("accept");
 72             exit(errno);
 73         } else
 74             printf("server: got connection from %s, port %d, socket %d ",
 75                    inet_ntoa(their_addr.sin_addr),
 76                    ntohs(their_addr.sin_port), new_fd);
 77 
 78         /* 开始处理每个新连接上的数据收发 */
 79         printf
 80      (" 准备就绪,可以开始聊天了……输入消息回车即可发信息给对方 ");
 81         while (1) {
 82             /* 把集合清空 */
 83             FD_ZERO(&rfds);
 84             /* 把标准输入句柄0加入到集合中 */
 85             FD_SET(0, &rfds);
 86             maxfd = 0;
 87             /* 把当前连接句柄new_fd加入到集合中 */
 88             FD_SET(new_fd, &rfds);
 89             if (new_fd > maxfd)
 90                 maxfd = new_fd;
 91             /* 设置最大等待时间 */
 92             tv.tv_sec = 1;
 93             tv.tv_usec = 0;
 94             /* 开始等待 */
 95             retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
 96             if (retval == -1) {
 97                 printf("将退出,select出错! %s", strerror(errno));
 98                 break;
 99             } else if (retval == 0) {
100                 /* printf
101               ("没有任何消息到来,用户也没有按键,继续等待…… "); */
102                 continue;
103             } else {
104                 if (FD_ISSET(0, &rfds)) {
105                     /* 用户按键了,则读取用户输入的内容发送出去 */
106                     bzero(buf, MAXBUF + 1);
107                     fgets(buf, MAXBUF, stdin);
108                     if (!strncasecmp(buf, "quit", 4)) {
109                         printf("自己请求终止聊天! ");
110                         break;
111                     }
112                     len = send(new_fd, buf, strlen(buf) - 1, 0);
113                     if (len > 0)
114                         printf
115                       ("消息:%s 发送成功,共发送了%d个字节! ",
116                              buf, len);
117                     else {
118                         printf
119                  ("消息'%s'发送失败!错误代码是%d,错误信息是'%s' ",
120                              buf, errno, strerror(errno));
121                         break;
122                     }
123                 }
124                 if (FD_ISSET(new_fd, &rfds)) {
125      /* 当前连接的socket上有消息到来则接收对方发过来的消息并显示 */
126                     bzero(buf, MAXBUF + 1);
127                     /* 接收客户端的消息 */
128                     len = recv(new_fd, buf, MAXBUF, 0);
129                     if (len > 0)
130                         printf
131                       ("接收消息成功:'%s',共%d个字节的数据 ",
132                              buf, len);
133                     else {
134                         if (len < 0)
135                             printf
136                    ("消息接收失败!错误代码是%d,错误信息是'%s' ",
137                                  errno, strerror(errno));
138                         else
139                             printf("对方退出了,聊天终止 ");
140                         break;
141                     }
142                 }
143             }
144         }
145         close(new_fd);
146         /* 处理每个新连接上的数据收发结束 */
147         printf("还要和其它连接聊天吗?(no->退出)");
148         fflush(stdout);
149         bzero(buf, MAXBUF + 1);
150         fgets(buf, MAXBUF, stdin);
151         if (!strncasecmp(buf, "no", 2)) {
152             printf("终止聊天! ");
153             break;
154         }
155     }
156 
157     close(sockfd);
158     return 0;
159 }

客户端程序如下:

//client.c

View Code
  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <errno.h>
  4 #include <sys/socket.h>
  5 #include <resolv.h>
  6 #include <stdlib.h>
  7 #include <netinet/in.h>
  8 #include <arpa/inet.h>
  9 #include <unistd.h>
 10 #include <sys/time.h>
 11 #include <sys/types.h>
 12 
 13 #define MAXBUF 1024
 14 
 15 int main(int argc, char **argv)
 16 {
 17     int sockfd, len;
 18     struct sockaddr_in dest;
 19     char buffer[MAXBUF + 1];
 20     fd_set rfds;
 21     struct timeval tv;
 22     int retval, maxfd = -1;
 23 
 24     if (argc != 3) {
 25         printf
 26         ("参数错误!正确用法如下: %s IP地址 端口 比如: %s 127.0.0.1 80 此程序从某个IP地址的服务器某个端口接收最多MAXBUF个字节的消息",
 27              argv[0], argv[0]);
 28         exit(0);
 29     }
 30     /* 创建一个 socket 用于 tcp 通信 */
 31     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
 32         perror("Socket");
 33         exit(errno);
 34     }
 35 
 36     /* 初始化服务器端(对方)的地址和端口信息 */
 37     bzero(&dest, sizeof(dest));
 38     dest.sin_family = AF_INET;
 39     dest.sin_port = htons(atoi(argv[2]));
 40     if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) {
 41         perror(argv[1]);
 42         exit(errno);
 43     }
 44 
 45     /* 连接服务器 */
 46     if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
 47         perror("Connect ");
 48         exit(errno);
 49     }
 50 
 51     printf
 52    (" 准备就绪,可以开始聊天了……输入消息回车即可发信息给对方 ");
 53     while (1) {
 54         /* 把集合清空 */
 55         FD_ZERO(&rfds);
 56         /* 把标准输入句柄0加入到集合中 */
 57         FD_SET(0, &rfds);
 58         maxfd = 0;
 59         /* 把当前连接句柄sockfd加入到集合中 */
 60         FD_SET(sockfd, &rfds);
 61         if (sockfd > maxfd)
 62             maxfd = sockfd;
 63         /* 设置最大等待时间 */
 64         tv.tv_sec = 1;
 65         tv.tv_usec = 0;
 66         /* 开始等待 */
 67         retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
 68         if (retval == -1) {
 69             printf("将退出,select出错! %s", strerror(errno));
 70             break;
 71         } else if (retval == 0) {
 72             /* printf
 73                ("没有任何消息到来,用户也没有按键,继续等待…… "); */
 74             continue;
 75         } else {
 76             if (FD_ISSET(sockfd, &rfds)) {
 77          /* 连接的socket上有消息到来则接收对方发过来的消息并显示 */
 78                 bzero(buffer, MAXBUF + 1);
 79               /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */
 80                 len = recv(sockfd, buffer, MAXBUF, 0);
 81                 if (len > 0)
 82                     printf
 83                         ("接收消息成功:'%s',共%d个字节的数据 ",
 84                          buffer, len);
 85                 else {
 86                     if (len < 0)
 87                         printf
 88                     ("消息接收失败!错误代码是%d,错误信息是'%s' ",
 89                              errno, strerror(errno));
 90                     else
 91                         printf("对方退出了,聊天终止! ");
 92                     break;
 93                 }
 94             }
 95             if (FD_ISSET(0, &rfds)) {
 96                 /* 用户按键了,则读取用户输入的内容发送出去 */
 97                 bzero(buffer, MAXBUF + 1);
 98                 fgets(buffer, MAXBUF, stdin);
 99                 if (!strncasecmp(buffer, "quit", 4)) {
100                     printf("自己请求终止聊天! ");
101                     break;
102                 }
103                 /* 发消息给服务器 */
104                 len = send(sockfd, buffer, strlen(buffer) - 1, 0);
105                 if (len < 0) {
106                     printf
107                  ("消息'%s'发送失败!错误代码是%d,错误信息是'%s' ",
108                          buffer, errno, strerror(errno));
109                     break;
110                 } else
111                     printf
112                       ("消息:%s 发送成功,共发送了%d个字节! ",
113                          buffer, len);
114             }
115         }
116     }
117     /* 关闭连接 */
118     close(sockfd);
119     return 0;
120 }

编译过程:gcc -Wall server.c -o server
         gcc -Wall client.c -o client

运行:在一个终端里运行  ./server 3490 1  模拟服务器端,其中3490指本地接口
     在另一个终端运行  ./client 127.0.0.1 3490  模拟客户端,最后一个参数应与服务器定义的接口相同

posted @ 2012-06-15 21:47  博临天下  阅读(2751)  评论(0编辑  收藏  举报