UNIX网络编程_第1章_一个简单的时间获取程序

客户端

#include "unp.h"

int int main(int argc, char const *argv[])
 {
  int sockfd,in;
  char recvline[MAXLINE + 1];
  struct sockaddr_in servaddr;

  if(argc != 2)
  {
    err_quit("usage: a.out <IPaddress>");
  }
  if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) <0)
  {
    err_sys("socket error");
  }

  bzero(&sevaddr, sizeof(sevaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(13);
  if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
  {
    err_quit("inet_pton error for %s", argv[1]);
  }
  if(connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
  {
    err_sys("connect error");
  }

  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(0);

  return 0;
}

1)socket函数创建一个网际(AF_INET)字节流(SOCK_STREAM)套接字,该函数返回一个小整数描述符,以后的所有函数调用就用该描述符来标识这个套接字。

2)err_开头的若干函数均由自行编写,err_sys函数输出我们作为参数提供的出错消息以及所发生的系统错误的描述,然后终止进程。

3)我们把服务器的IP地址和端口号填入一个网际套接字地址结构(一个名为servaddr的sockaddr_in结构变量)。使用bzero把整个结构清零后,置地址族为AF_INET,端口号为13(时间获取服务器众所周知的端口),IP地址为第一个命令行参数的值(argv[1])。网际套接字地址结构中IP地址和端口号这两个成员必须使用特定格式,为此我们调用库函数htons("主机到网络短整数")去转换二进制端口号,又调用库函数inet_pton("呈现形式到数值")去把ASCII命令行参数转换为合适的格式。

4)connect函数应用于一个TCP套接字时,将与由它的第二个参数指向的套接字地址结构指定的服务器建立一个TCP连接。该套接字地址结构的长度也必须作为该函数的第三个参数指定,对于网际套接字地址结构,我们总是用C语言的sizeof操作符由编译器来计算这个长度。

5)在头文件unp.h中,使用了#define把SA定义为了struct sockaddr。

6)使用read函数读取服务器的应答,并使用标准的IO函数fputs输出结果。使用TCP时必须小心,因为TCP是一个没有记录边界的字节流协议。一条26个字节的应答,可以有多种返回方式,既可以是包含所有26字节的单个TCP分节,也可以是每个分节只含有1个字节的26个TCP分节,还可以是其他的任何组合。通常服务器返回包含所有26个字节的单个分节,但如果数据量很大,我们就不能确保一次read调用能返回整个应答,因此从TCP套接字读取数据时,我们总是需要把read编写在某个循环中,当read返回0(表明对端关闭连接)或负值(表明发生错误)时终止循环。

7)exit终止程序运行。Unix在一个进程终止时总是关闭该进程所有打开的描述符,我们的TCP套接字就此被关闭。

服务端

#include "unp.h"
#include <time.h>

int int main(int argc, char const *argv[])
 {
  int listenfd,connfd;
  struct sockaddr_in servaddr;
  char buff[MAXLINE];
  time_t ticks;

  listenfd = Socket(AF_INET, SOCK_STREAM, 0);

  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(13);

  Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

  Listen(listenfd, LISTENQ);

  for( ; ; )
  {
    connfd = Accept(listenfd, (SA *) NULL, NULL);

    ticks = time(NULL);
    snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
    Write(connfd, buff, strlen(buff));

    Close(connfd);
  }

  return 0;
}

1)调用listen函数把该套接字转换成一个监听套接字,这样来自客户的外来连接就可在该套接字上由内核接受。socket,bind,listen这三个调用步骤是任何TCP服务器准备所有的监听描述符(listening descriptor,本例中为listenfd)的正常步骤。常值LISTENQ在我们的unp.h头文件中定义,它指定系统内核允许在这个监听描述符上排队的最大客户连接数。

2)通常情况下,服务器进程在accept调用中被投入睡眠,等待某个客户连接的到达并被内核接受。TCP连接使用的所谓的三路握手建立连接。握手完毕时accept返回,其返回值是一个称为已连接描述符的新描述符。该描述符用于与新近连接的那个客户通信。accept为每个连接到本服务器的客户返回一个新描述符。

3)当前时间和日期是由库函数time返回的,它实际上返回的是自Unix纪元即1970年1月1日0点0分0秒以来的秒数。下一个库函数ctime把该整数值转换成直观可读的时间格式。

4)snprintf要求其第二个参数指定目的缓冲区的大小,因此可确保该缓冲区不溢出。

5)close调用后关闭与客户的连接。该调用引发正常的TCP连接终止序列:每个方向上发送一个FIN,每个FIN又由各自的对端确认。

6)本服务器一次只能处理一个客户。如果多个客户连接差不多同时到达,系统内核在某个最大数目的限制下把它们排入队列,然后每次返回一个accept函数。本服务器只需调用time和ctime两个函数,运行速度很快。然而如果服务器需用较多时间服务每一个客户,那么我们必须以某种方式重叠对各个客户的服务。如上所示的服务器成为迭代服务器,因为对于每个客户它都迭代执行一次。同时能处理多个客户的并发服务器由多种编写技术。最简单的技术是调用Unix的fork函数,为每个客户创建一个子进程。其他技术包括使用线程代替fork,或在服务器启动时预先fork一定数量的子进程。

7)如果shell命令行启动本例的服务器,我们也许想要它运行很长时间。因为服务器往往在系统工作期间一直运行。这要求我们往服务器程序中添加代码,以便它能够作为一个Unix守护进程(daemin)--能在后台运行且不跟任何终端关联的进程--运行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容

  • 1、TCP状态linux查看tcp的状态命令:1)、netstat -nat 查看TCP各个状态的数量2)、lso...
    北辰青阅读 9,423评论 0 11
  • 最近在看《UNIX网络编程 卷1》和《FREEBSD操作系统设计与实现》这两本书,我重点关注了TCP协议相关的内容...
    腩啵兔子阅读 1,160评论 0 7
  • 《UNIX 网络编程卷一:套接字联网API》笔记 套接字 套接字编程接口,是在 TCP/IP 协议族中,应用层进入...
    超net阅读 5,793评论 2 13
  • 之前拍过的下雨天的照片,来个小合集。 国庆小长假过后,天气更冷了~ 总觉得因为有雨,喧闹浮躁中多了几分沉静~ 整个...
    喜悦Iris阅读 1,082评论 0 0
  • 我很幸运25岁的我还是单身,一个人生活上下班,做自己喜欢吃的食物给自己,看自己喜欢的书,听自己喜欢的音乐,恣意在家...
    WonderfulR阅读 113评论 0 0