Linux网络编程学习笔记_1_一个简单的时间获取服务器/客户端程序及解析
终于自己也可以写出一个服务器/客户端程序,虽然很简单,虽然只是Richard Stevens大神代码的简单复制,但是对于我来说确实一件开天劈地的大事,因为这是第一个,他让我意识到自己原来也可以写网络程序!
好了,废话不多说,代码如下:
1、服务器端:
#include "unp.h" #include <time.h> int main(int argc,char **argv) { int listenfd,connfd; struct sockaddr_in servaddr; char buff[MAXLINE]; time_t ticks; /* 创建一个网际(AF_INET)字节流(SOCK_STREAM)套接字, 并以listenfd返回其描述符。 */ listenfd = Socket(AF_INET,SOCK_STREAM,0); /* 通过填写一个网际套接字地址结构并调用bind函数,将服务器的一个端口 绑定到所创建的套接字上。 */ bzero(&servaddr,sizeof(servaddr));//bzero将整个结构体清零 servaddr.sin_family = AF_INET;//将地址族设置为AF_INET /* INADDR_ANY:指定IP地址为INADDR_ANY,这样要是服务器主机 有多个网络接口,服务器进程就可一在任意网路接口上接受连接。 */ servaddr.sin_addr.s_addr =htonl(INADDR_ANY); /* 将服务器开放的端口设定为9999,原文中设定的是13, 如果按照原文的示例,则该程序运行时需要获取root权限,才能申请使用13号端口 但是在将服务器开放端口设为9999之后,需要在客户端程序的访问端口处, 改为9999,不然会出现访问受限的情况! 网际套接字地址结构中IP地址和端口号这两个成员必须使用特定格式, 为此我们使用htons("主机到网络短整数")去转换二进制端口号。 */ servaddr.sin_port = htons(9999); Bind(listenfd,(SA *) &servaddr,sizeof(servaddr)); /* 调用listen函数将该套接字转换成一个监听套接字, 这样来自客户的外来连接就可以在该套接字上有内核接受 */ //LISTENQ指定系统内核允许在这个监听描述符上排队的最大客户连接数 Listen(listenfd,LISTENQ); /* 接受客户连接,发送应答 */ for(;;) { /* TCP的三路握手,进行连接。 完成TCP连接之后,accept函数返回一个“已连接描述符” 该描述符用于与新近连接的那个客户端进行通信。 accept为每个连接到本服务器的客户返回一个新的描述符。 */ connfd = Accept(listenfd,(struct sockaddr *)NULL,NULL); //获取当前系统时间 ticks = time(NULL); //ctime将整数值转换成直观可读的时间格式 snprintf(buff,sizeof(buff),"%.24s\r\n",ctime(&ticks)); //write函数将把结果字符串写给客户 Write(connfd,buff,strlen(buff)); //终止连接,TCP的四次挥手 Close(connfd); } exit(0); }
2、客户端
#include "unp.h" int main(int argc,char **argv) { //如果程序参数格式不正确 if (argc != 2) { err_quit("usage: a.out <IPaddress>"); } //创建一个TCP套接字,返回sockfd作为套接字描述符 int sockfd; if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) { err_sys("socket error"); } /* 指定服务器的IP地址与端口 */ struct sockaddr_in servaddr; bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(9999);//解释见服务器程序 //inet_pton("呈现形式到数值"),把ASCII命令行参数转换为合适的格式 //argv[1]代表服务器IP地址 if (inet_pton(AF_INET,argv[1],&servaddr.sin_addr) < 0) { err_quit("inet_pton err for %s",argv[1]); } /* 建立与服务器的连接 connect函数应用于一个TCP套接字时,将与由他的第二个参数只想的套接字地址结构 指定的服务器建立一个TCP连接。 在unp.h头文件中,将SA定义为struct sockaddr。 */ if (connect(sockfd,(SA *)&servaddr,sizeof(servaddr)) < 0) { err_sys("connect error"); } /* 读入并输出服务器的应答: **使用TCP时必须小心,因为TCP是一个没有记录边界的字节流协议 */ int n; char recvline[MAXLINE + 1]; //如果数据量很大,我们不能保证一次read就可一返回服务器的所有应答。 //当read返回0(对端关闭连接)或者负值(发生错误)时,终止循环。 while ((n = read(sockfd,recvline,MAXLINE)) > 0) { recvline[n] = 0; if (fputs(recvline,stdout) == EOF) { err_sys("fputs error"); } } if (n < 0) { err_sys("read error"); } /* exit终止程序运行,UNIX在一个进程终止时总是关闭该进程所有打开的 描述符,我们的TCP套接字就此关闭! */ exit(0); }
3、运行效果
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。