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  模拟客户端,最后一个参数应与服务器定义的接口相同

你可能感兴趣的:(linux)