Unix网络编程卷1 读书笔记 第一章 简介

0.概要简介

本章介绍了服务器-客户端的基本架构,socket套接字,从OSI模型层面分析socke的作用,提供了一个时间服务的客户端和服务端的最小实现。本章学完后应该对网络编程有一个直观的印象。


image.png

重点是1,2,5,7节。

1.知识总结

1.1 客户端-服务端架构

要编写通过计算机网络通信的程序,首先要确定这些程序相互通信所用的协议(protocol)。在深入设计一个协议的细节之前,应该从高层次决断通信由哪个程序发起以及响应在何时产生。举例来说,一般认为Web服务器程序是一个长时间运行的程序(即所谓的守护程序,daemon),它只在响应来自网络的请求时才发送网络消息。协议的另一端是Web客户程序,如某种浏览器,与服务器进程的通信总是由客户进程发起。大多数网络应用就是按照划分成客户(client)和服务器(server)来组织的。

1.2 OSI模型与socket编程接口

OSI的7层模型是老生常谈的内容了,但是之前每次看的时候仅限于记忆,并没有深入的理解。


图片发自简书App

对于一个新的事物如果仅仅是记忆概念,对之没有其他更多的操作实践,那么算不上理解掌握了它。之前也接触过OSI的7层模型,但总是感觉概念无法实际落地。看完本章关于socket编程接口和协议模型的论述,对协议觉理解加深了一步。简单的说socket编程接口是上三层(应用层、表示层、会后层)进入传输层的接口。

本书讲述的套接字编程接口是从顶上三层(网际协议的应用层)进入传输层的接口。本书的焦点是:如何使用套接字编写使用TCP或者UDP的网络应用程序。

1.3 socket编程客户端-服务端基本流程

图片发自简书App

2.动手实验

本章实验基于安装了Ubuntu系统的台式机和安装了lubuntu系统的cubieboard cc-a80开发板,进行两个实验:

  • 客户端实验
    实现一个客户端程序,在Ubuntu系统以系统自带的时间服务为服务端,获取时间。
  • 服务端实验
    实现一个服务端程序,将该服务端程序部署在cc-a80,使用上个实验中的位于Ubuntu系统的客户端向 cc-a80服务器端发出请求获取时间。

2.1 实验代码

作者在前言中已经给出了书中代码的下载地址,但我总觉得还是自己手动敲一遍理解更深。作者把常用的头文件、错误处理、socket接口均封装成响应的文件,实验学习过程代码组织目录结构保持和书中一致,具体实现本着用到什么实现什么的原则。为了分享,笔者在github上建立一个仓库,地址如下:
https://github.com/Sam-Z/unix_network_programming_volume_1.git

├── intro
│ ├── daytimetcpcli.c
│ ├── daytimetcpcli.mk
│ ├── daytimetcpsrv.c
│ └── daytimetcpsrv.mk
├── lib
│ ├── libwrapsock.mk
│ ├── unp.h
│ └── wrapsock.c

目录结构如下,intro目录下是第一章的两个程序所在目录,在该目录下提供了两个makefile,例如执行

make -f daytimetcpcli.mk

就可以编译获取时间的客户端程序,服务端的程序类似。lib目录是库函数目录,当前只有socket接口的包裹函数和unp.h头文件,后续随着学习的深入,逐渐完善。本书的后续学习实验代码均会更新到该仓库。

为了便于后续服务端实验,在客户端和服务端的程序将端口号统一用MY_DAY_TIME_SERVER_PORT宏给出,第一个实验中该宏设置为13(系统时间服务端口号固定为13),第二个实验中该宏设置为一个未被使用的端口即可(笔者实验代码中使用的是45000)。

2.2获取时间客户端

  • 源码
#include"unp.h"
#define MAXLINE (256)
int main(int argc, char **argv)
{
    // 1. 参数校验
    if (argc != 2){
        printf("usage: a.out <IPaddress>\n");
        exit(0);
    }

    // 2. 建立socket
    int sockfd = 0;
    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        printf("socket error!\n");
        exit(0);
    }

    // 3. 建立连接
    struct sockaddr_in  addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port   = htons(MY_DAY_TIME_SERVER_PORT);
    if (inet_pton(AF_INET, argv[1], &addr.sin_addr) < 0){
        printf("inet_pton error for %s\n", argv[1]);
        exit(0); 
    }
    if ( connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0){
        printf("connect error!\n");
        exit(0); 
    }

    // 4. 读取数据
    char recvline[MAXLINE+1];
    int n = 0;
    while( (n = read(sockfd, recvline, MAXLINE)) > 0 ){
        recvline [n] = 0;
        printf("%s\n", recvline);
    }

    if (n<0){
        printf("read error!\n");
    }

    exit(0);
}
  • 执行
    在Ubuntu源码编译生成可执行文件后,按照如下命令执行,127.0.0.1是本地回环IP地址,即从本地电脑的系统服务获取时间。
$ daytimetcpcli 127.0.0.1

执行过程出现如下错误。

connect error!

百度一番,有人说是由于系统的时间服务未开启,按照如下操作开启系统时间服务。
安装服务

apt-get install xinetd

配置

 sudo vi /etc/xinetd.d/daytime

将其中的disable 值改为no。
重启服务

sudo /etc/init.d/xinetd restart 

再次执行,正常获取到时间,结果如下

$ daytimetcpcli  127.0.0.1
31 DEC 2017 14:38:36 CST

2.3 获取时间服务端实验

  • 源码
#include "unp.h"
#include <time.h>

int main(int argc, char **argv)
{
    int listenfd, connfd;
    struct sockaddr_in servaddr;
    char buffer[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(MY_DAY_TIME_SERVER_PORT);

    Bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

    Listen(listenfd, LISTENQ);

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

        ticks = time(NULL);

        snprintf(buffer, sizeof(buffer), "MY_DAY_TIME_SERVER:%s.24s\n", ctime(&ticks));

        Write(connfd, buffer, strlen(buffer));

        Close(connfd);
    }
}
  • 执行
    源码在cc-a80环境编译生成可执行文件,启动服务程序。
linaro@cubieboard4:~$ daytimetcpsrv&

Ubuntu端使用客户端发起访问

$ daytimetcpcli 192.168.20.100
MY_DAY_TIME_SERVER:Sun Dec 31 14:26:28 2017

这里的192.168.20.100是cc-a80的IP地址。

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

推荐阅读更多精彩内容

  • iOS网络HTTP、TCP、UDP、Socket 知识总结OSI 七层模型我们一般使用的网络数据传输由下而上共有七...
    蜗牛也有梦想阅读 2,356评论 0 3
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 姓名:王建勛 公司:思沃技术171期利他2组王建勋 211期志工 【知-学习】 诵《六项精进》大纲5遍,共514遍...
    常修阅读 191评论 0 0
  • 文/我叫o泡 上了大学选择了一份专业,将来就只能靠这一份专业安身立命养家糊口?十八九岁懵懂时选择的那份专业,能顶得...
    我叫O泡阅读 1,538评论 3 9