第四篇:一对经典的时间获取客户/服务器程序

前言

       本文通过一对经典的时间获取客户/服务器程序,展现了Linux网络编程的大体框架,为以后更深入的学习打下基础。

客户服务器模式网络编程的大体框架

       

客户端代码

 1 #include <stdio.h>
 2 // 下头文件包含socket(), bind()等套接字通信必须的函数。
 3 #include <sys/socket.h>
 4 // 下头文件包含网际套接字变量的类型定义等。
 5 #include <netinet/in.h>
 6 // 下头文件包含bzero()函数等
 7 #include <string.h>
 8 // 下头文件包含errno变量等
 9 #include <errno.h>
10 
11 #define MAXLINE 100 
12 
13 int main (int argc, char ** argv)
14 {
15     // 定义套接字描述符变量sockfd
16     // 定义变量n存放read函数返回值
17     int sockfd, n;
18     // 定义字符数组recvline存放时间查询结果
19     char recvline[MAXLINE + 1];
20     // 定义套接字变量servaddr( 注意这里存放的是服务器端的信息 )
21     struct sockaddr_in servaddr;
22 
23     // 检查命令格式是否正确
24     if (argc != 2) {
25         puts("命令格式错误\n");
26         return 1;
27     }
28     
29     // 创建一个网际字节流套接字
30     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) <0) {
31         puts("网际套接字创建失败\n");
32         return 2;
33     }
34 
35     // 将套接字变量servaddr清零
36     bzero(&servaddr, sizeof(servaddr));
37     // 给套接字变量的协议段赋值( AF_INET表示IPv4协议 )
38     servaddr.sin_family = AF_INET;
39     // 给套接字变量的端口段赋值( 13是时间服务器端口 )
40     servaddr.sin_port = htons(13);
41     // 给套接字变量的IP段赋值( argv[1]存放服务器IP )
42     if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
43         puts("IP地址格式转换失败");
44         return 3;
45     }
46 
47     // 按照先前socket函数指定的协议类型与服务器进行连接
48     if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
49         puts("连接失败\n");
50         return 4;
51     }
52 
53     // 从缓冲区读取时间查询结果并放进recvline数组中
54     if ( (n = read(sockfd, recvline, MAXLINE)) > 0 ) {
55         recvline[n] = 0;
56         puts(recvline);
57     }
58     if (n < 0) {
59         puts("读取数据发生错误");
60     }
61 
62     return 0;
63 }

服务器端代码

 1 #include <stdio.h>
 2 
 3 // 下头文件包含socket(), bind()等套接字通信必须的函数。
 4 #include <sys/socket.h>
 5 // 下头文件包含网际套接字变量的类型定义等。
 6 #include <netinet/in.h>
 7 // 下头文件包含bzero()函数等
 8 #include <string.h>
 9 // 下头文件包含errno变量等
10 #include <errno.h>
11 // 下头文件包含一些时间函数
12 #include <time.h>
13 
14 #define MAXLINE 100 
15 #define LISTENQ 5
16 
17 int main(int argc, char **argv)
18 {
19     // 定义监听套接字描述符listenfd
20     // 定义连接套接字描述符
21     int listenfd, connfd;
22     // 定义套接字变量servaddr( 注意这里存放的是客户端的信息 )
23     struct sockaddr_in servaddr;
24     // 定义字符数组buff暂存时间
25     char buff[MAXLINE];
26 
27     // 定义时间相关变量
28     time_t ticks;
29     struct tm *ptm;
30 
31     // 创建一个网际字节流套接字
32     if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
33         puts("创建网际套接字失败\n");
34         return 1;
35     }
36 
37     // 将套接字变量servaddr清零
38     bzero(&servaddr, sizeof(servaddr));
39     // 给套接字变量的协议段赋值( AF_INET表示IPv4协议 )
40     servaddr.sin_family = AF_INET;
41     // 给套接字变量的端口段赋值( 13是时间服务器端口 )
42     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
43     // 给套接字变量的IP段赋值( argv[1]存放服务器IP )
44     servaddr.sin_port = htons(13);
45 
46     // 把指定的协议地址绑定到套接字
47     if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
48         puts("绑定服务端口失败\n");
49         return 2;
50     }
51     // 将套接字转换为监听套接字类型
52     if (listen(listenfd, LISTENQ) < 0) {
53         puts("创建监听套接字失败\n");
54         return 3;
55     }
56 
57     while (1) {
58         // 等待客户呼叫,若收到呼叫则返回一个已连接套接字。
59         connfd = accept(listenfd, (struct sockaddr *)NULL, NULL);
60 
61         /*
62          * 获取时间并存放进buff数组
63         */
64         ticks = time(NULL);
65         ptm = localtime(&ticks);
66         snprintf(buff, sizeof(buff), "现在是北京时间:\n%d年 %d月 %d日 %d时 %d分", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min);
67 
68         // 往客户端缓冲区中写入时间
69         while (write(connfd, buff, strlen(buff)) < 0) {
70             puts("写入数据失败\n");
71             return  4;
72         }
73         // 关闭连接
74         if (close(connfd)) {
75             puts("关闭套接字失败\n");
76             return 5;
77         }
78     }
79 }

运行测试

       1. 在一个终端用超级用户权限启动服务器:

       

       2. 在另一个终端中启动客户端并输进本机IP或者127.0.0.1:

       

posted @ 2017-01-29 11:55  穆晨  阅读(640)  评论(0编辑  收藏  举报