unix网络编程卷一: 从服务器获取时间信息(一)-代码解析

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;//从服务器读取n个数,然后再在后面添加结束符,为下面fputs能正常输出准备(fputs不自动写入字符串结束标记符‘\0’    if (fputs(recvline,stdout) == EOF)
    {
      err_sys("fputs error");
    }
  }
  if (n < 0)
  {
    err_sys("read error");
  }

  /*
  exit终止程序运行,UNIX在一个进程终止时总是关闭该进程所有打开的
  描述符,我们的TCP套接字就此关闭!
  */
  exit(0);
}
http://www.tuicool.com/articles/YJzMZn
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值