前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >网络编程-一个简单的echo程序(1)

网络编程-一个简单的echo程序(1)

作者头像
编程珠玑
发布于 2019-07-12 06:57:37
发布于 2019-07-12 06:57:37
1K00
代码可运行
举报
文章被收录于专栏:编程珠玑编程珠玑
运行总次数:0
代码可运行

前言

在《网络编程-一个简单的echo程序(0)》中已经对程序整体有了宏观的认识,本文将抽丝剥茧,逐步深入了解echo程序。

程序代码

由于代码内容较多,具体代码可访问《网络编程-一个简单的echo程序(0)》或者访问: https://www.yanbinghu.com/2019/07/07/40135.html

数据结构与函数详解

既然要详细了解echo程序,就必须对其中用到的一些数据结构和接口有所了解。在echo程序中,我们主要用到了以下的数据结构或函数:

  • htons/ntohs
  • inet_pton/inet_ntop
  • sockaddr_in
  • socket
  • bind
  • listen
  • connect
  • accept

当然需要清楚的是,网络编程中用到的数据结构或函数远不止上面提到的这些,但这些都是最基本的。下面的解释都基于echo程序,多数函数都使用默认的阻塞模式。

htons/ntohs

htons/ntohs这两个宏分别用于将本地字节序转为网络字节序和将网络字节序转为本地字节序。关于字节序,本文不展开介绍,可以参考《谈一谈字节序的问题》,如何判断当前机器的字节序,也是面试中经常到的题目。

inet_pton/inet_ntop

inet_pton/inet_ntop分别用于将字符串ip地址转为4字节大小的无符号整型和将无符号整型转换为ip地址字符串。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//来源:公众号【编程珠玑】网站:https://www.yanbinghu.com
#include<stdio.h>
#include <arpa/inet.h>
int main(void)
{
    char ip[16] = "192.168.0.1";
    struct in_addr addr;
    inet_pton(AF_INET, ip, &addr);
    printf("addr is %x\n",addr);

    addr.s_addr = 0x153a8c0;
    inet_ntop(AF_INET,&addr,ip,sizeof(ip));
    printf("ip is %s",ip);
    return 0;
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
addr is 100a8c0                                                                 
ip is 192.168.83.1

从运行结果中可以清晰看到两者之间的转换。需要注意的是,inet_pton/inet_ntop对IPV4和IPV6地址都适用。

sockaddr_in

sockaddr_in是IPV4套接字地址结构,它在不同系统中具体定义可能有所不同:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct sockaddr_in{
    sa_family_t sin_family;
    in_port_t sin_port;
    struct in_addr sin_addr;
    char sin_zero[8];
};

但它们都包含三个基本的成员:

  • sin_family 协议族
  • sin_port 协议端口
  • sin_addr 协议地址

协议族通常有以下几种类型:

  • AF_INET IPV4协议
  • AF_INET6 IPV6协议
  • AF_LOCAL Unix域协议
  • AF_ROUTE 路由套接字
  • AF_KEY 秘钥套接字

而目前echo程序中用到的是IPV4协议,因此选择了AF_INET。

而sin_port就比较容易理解了,它是一个16比特大小的端口,但是由于它的信息需要在网络中传输,因此需要使用前面介绍的htons进行字节序的转换。

sin_addr用4字节存储ip地址,如果是形如127.0.0.1的地址,需要通过inet_pton函数将其转换为struct in_addr类型。

socket--确定协议族和套接字类型

调用socket函数是执行网络I/O之前必须做的一件事情。通过socket函数指定了本次网络通信的协议族,套接字类型,调用成功后,会返回一个非负的套接字描述符,否则返回-1,具体失败原因,被存放于全局变量errno。它和文件描述类似,只不过此时它还不能进行正常的网络读写。 socket函数相关信息如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<sys/socket.h>
int socket(int family,int type,int protocol);

其中family就是在介绍sockaddr_in中提到的协议族。

type通常有以下几个值:

  • SOCK_STREAM 字节流套接字
  • SOCK_DGRA 数据报套接字
  • SOCK_RAW 原始套接字
  • SOCK_SEQPACKET 有序分组套接字
  • SOCK_PACKET 分组套接字

需要注意的是:

  • TCP仅支持字节流套接字
  • UDP仅支持数据报套接字
  • SCTP支持字节流套接字和数据报套接字

protocol通常指以下几种:

  • IPPROPO_TCP TCP协议
  • IPPROPO_UDP UDP协议
  • IPPROPO_SCTP SCTP协议

通常来说,一种传输协议只支持一种套接字,此时protocol可以为0,系统会选择其对应的协议类型;否则的话,需要指定protocol的值。在当前echo程序中,type为SOCK_STREAM,我们的protocol值为0,因此使用的就是TCP协议。

我们通过一个简单的例子,观察这个套接字描述符:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//testSocket.c
//来源:公众号【编程珠玑】网站:https://www.yanbinghu.com
#include<stdio.h>
#include <arpa/inet.h>
#include<unistd.h>
int main(void)
{
    int socktfd = socket(AF_INET,SOCK_STREAM,0);
    sleep(20);
    return 0;
}

在一个终端运行testSocket,在另外一个终端找到该程序的pid,并查看打开的文件描述符:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ pidof testSocket
5903
$ ls -l /proc/5903/fd/
total 0
lrwx------ 1 hyb hyb 64 78 19:59 0 -> /dev/pts/6
lrwx------ 1 hyb hyb 64 78 19:59 1 -> /dev/pts/6
lrwx------ 1 hyb hyb 64 78 19:59 2 -> /dev/pts/6
lrwx------ 1 hyb hyb 64 78 19:59 3 -> socket:[62182]

还记得那句话吗:linux下一切皆文件。

bind--指定套接字地址信息

调用socket函数之后已经确定了协议族和传输协议,但是还没有确定本地协议,即套接字地址信息。bind函数描述如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<sys/socket.h>
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);

sockfd是前面调用socket函数返回的套接字描述符,用于将协议地址绑定到指定套接字中去,返回0表明成功,-1表示失败,具体失败原因,被存放于全局变量errno。addr是套接字地址,它并不是我们前面所看到的sockaddr_in类型,而是struct sockaddr,因为struct sockaddr是通用类型,不仅适用于IPV4套接字地址,也需要适用于IPV6套接字地址。

addr中的ip地址可以为0(INADDR_ANY),表示使用通配地址;而端口为0,表示由内核分配一个临时端口。服务器需要被客户端连接,因此其端口通常都是确定的,不会选择一个临时端口。

但是在客户端其ip地址和端口并非需要确切知道,因此客户端常常不绑定端口。在我们的echo程序中,我们也没有在客户端调用bind函数。

listen--监听客户端连接

listen函数用于将前面得到的套接字变为一个被动套接字,即可用于接受来自客户端的连接。描述如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<sys/socket.h>
int listen(int sockfd,int backlog);

返回0表明成功,-1表明失败,具体失败原因,被存放于全局变量errno。sockfd就是socket函数调用返回的套接字描述符,而backlog指明了连接队列的大小,即完成和还未完成TCP三次握手的连接总和。如果这个队列满了,服务器就不会理会新的连接请求。还记得在《网络编程-从TCP连接的建立说起》中提到的SYN攻击吗?

connect--建立连接

connect函数在客户端调用,它用来与服务端建立连接。描述如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<sys/socket.h>
int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);

返回0表明成功,-1表明失,具体失败原因,被存放于全局变量errno。connect函数的参数与bind函数一样,这里就不多做解释了,只不过addr指明的是远端协议地址。如果本次连接是TCP协议,则connect函数调用将会发起TCP的三次握手

accept--接受来自客户端的连接

accept函数在服务端调用,它用于接受来自客户端的连接,从已完成连接队列返回一个已完成连接。描述如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<sys/socket.h>
int accept(int sockfd,const struct sockaddr *addr,socklen_t addrlen);

成功返回非负套接字描述符,失败返回-1,具体失败原因,被存放于全局变量errno。需要注意的是accept函数参数类型和数量与connect函数一致,但是含义不同,addr用于获取客户端的套接字地址信息,如果不关心客户端的协议地址,那么该参数可为NULL。

另外需要注意的是,它的返回值是一个非负的套接字描述符,这个套接字描述符是已连接套接字描述符,而其参数sockfd是监听套接字描述符。一个服务器通常一直有且只有一个监听套接字描述符,但通常会有多个已连接套接字描述符。还记得在《网络编程-一个简单的echo程序(0)》中问到的吗?为什么客户端连接到服务端后,服务端有一个处于LISTEN状态,还有一个处于ESTABLISHED状态吗?

通过已连接套接字描述符就可以对其进行数据的读写了。

https://www.yanbinghu.com/2019/07/08/3270.html

再看echo程序

小结

本文主要对echo程序中用到的一些数据结构和函数进行了介绍,但没有涉及具体的异常场景,后面的文章将根据实际情况来看看其具体应用。本文常用总结如下:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程珠玑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
04 网络面经:HTTP 2.0的这些新特性,是时候了解一下了
面试中关于HTTP 2.0的面试题并不多,但基于HTTP 2.0的应用已经很多了,比如谷歌的gRPC框架就是基于HTTP 2.0来提升效率的。同时,HTTP 1.0中的存在的很多缺陷也都在HTTP 2.0中得到了解决。
程序新视界
2021/12/07
3520
04 网络面经:HTTP 2.0的这些新特性,是时候了解一下了
HTTP/3 竟然基于 UDP,HTTP 协议这些年都经历了啥?
花下猫语:若说最为人知的网络协议,大概非 HTTP 协议莫属。但是,关于这个协议的更多细节,相信很多人都答不上来。现在它已经发展到第三代了,而且出现了重大的转变。今天分享的这篇文章,主要从 HTTP 发展进化的角度,介绍了这个协议的底层原理以及设计思想,希望对你有所帮助。
Python猫
2019/04/23
1.6K0
HTTP/3 竟然基于 UDP,HTTP 协议这些年都经历了啥?
图解 HTTP 的前世今生!
Http超文本传输协议同空气一般,感触不到它的存在但是又无处不在,笔者从维基百科摘录了一些Http协议的发展历程的简单信息,一起来看下吧:
范蠡
2020/11/13
8560
图解 HTTP 的前世今生!
什么是http2.0?
上图:设置Connection:Keep-Alive,保持连接在一段时间内不断开。
小灰
2022/07/05
2.8K0
什么是http2.0?
二、《图解HTTP》- HTTP协议历史发展(重点)
这一章节基本上大部分为个人扩展,因为书中的内容讲的实在是比较浅。本文内容非常长,另外哪怕这么长也只是讲到了HTTP协议的一部分而已,HTTP协议本身十分复杂。
阿东
2022/08/12
6700
二、《图解HTTP》- HTTP协议历史发展(重点)
详解:HTTP协议的演进与特性
来源:Linux云计算网络 HTTP的前世传奇 HTTP协议确定之前,伯纳斯-李已经提出了超文本构想,并最终实现了最早期的超文本系统。 1980年——超文本构想的诞生 1980年6月至12月间,伯纳斯-李在日内瓦的CERN(欧洲核子研究中心)担任独立承包人。在那段时间里,他提出了一个构想:创建一个以超文本系统为基础的项目,目的是为了方便研究人员分享及更新讯息。 同时他也开发出了最早的原型系统,并命名为ENQUIRE。这个系统允许一个存储信息片断,并以任何方式链接相关的部分。要找到信息,通过从一张纸到另一张
SDNLAB
2022/08/26
4750
详解:HTTP协议的演进与特性
【HTTP】843- 揭秘 HTTP2
前段时间组内小伙伴遇到了一个问题:一个页面上有 10 个视频,因为浏览器对 tcp 连接数的限制,导致同时只能加载 6 个视频。考虑到http2协议的多路复用可以解决这个问题,特地整理此篇关于http2的内容和大家分享。
pingan8787
2021/01/28
1.6K0
【HTTP】843- 揭秘 HTTP2
HTTP 0.9 HTTP 1.0 HTTP 1.1 HTTP 2.0区别
HTTP协议 :Hyper Text Transfer Protocol(超文本传输协议),是用于从万维网(WWW:World Wide Web)服务器传输超文本到本地浏览器的传送协议。是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。 HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。 HTTP/0.9 HTTP/0.9是第一个版本的HTTP协议,已过时。它的组成极其简单,只允许客户端发送GET这一种请求,且不支持请求头。由于没有协议头,
武培轩
2018/04/18
1.7K0
HTTP/1.1和HTTP/2.0有什么区别
HTTP/1.1 和 HTTP/2.0 是 HTTP 协议的两个版本,它们之间有以下几点区别:
程序员朱永胜
2023/11/15
1.3K0
HTTP1.0、1.1、2.0、3.0的主要区别?HTTP状态码及含义?
HTTP头Connection: keep-alive是什么意思?解决了什么问题?
了凡银河系
2022/08/22
1.1K0
HTTP1.0、1.1、2.0、3.0的主要区别?HTTP状态码及含义?
HTTP/2学习笔记
上图中流A和B没有依赖关系,权重分别为12和4,则A和B获取资源的比例为3/4、1/4;C依赖于D,则D需要等待C后分配资源。
用户1472179
2019/04/01
1.3K0
真正“搞”懂HTTP协议13之HTTP2
  在前面的章节,我们把HTTP/1.1的大部分核心内容都过了一遍,并且给出了基于Node环境的一部分示例代码,想必大家对HTTP/1.1已经不再陌生,那么HTTP/1.1的学习基本上就结束了。这两篇文章,我会和大家一起,学习一下HTTP/2和HTTP/3。
zaking
2023/02/13
8160
真正“搞”懂HTTP协议13之HTTP2
HTTP 和 HTTPS 之间除了安全性区别外,还有哪些区别
HTTP 和 HTTPS 是两种常见的网络协议,它们都是用于在浏览器和服务器之间传输数据的。但是,它们之间也有一些重要的区别,这些区别涉及到数据的安全性、传输性能、使用成本和搜索排名等方面。本文将从以下几个方面来介绍 HTTP 和 HTTPS 的区别,本文内容大纲如下:
wayn
2023/11/28
5240
HTTP 和 HTTPS 之间除了安全性区别外,还有哪些区别
HTTP 2.0 为什么这么设计
HTTP 1.0 是 1996 年发布的,奠定了 web 的基础。时隔三年,1999 年又发布了 HTTP 1.1,对功能上做了扩充。之后又时隔十六年,2015 年发布了 HTTP 2.0。
神说要有光zxg
2022/06/06
3780
HTTP 2.0 为什么这么设计
透视http协议
HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范
虎妞先生
2023/10/16
2330
透视http协议
http协议
当客户端和服务器通过三次握手建立了TCP连接以后,当数据传送完毕,肯定是要断开TCP连接的啊。那对于TCP的断开连接,这里就有了神秘的“四次分手”。
愤怒的小鸟
2021/01/06
7260
谈谈HTTP1.0,HTTP1.1和HTTP2.0区别
HTTP协议(HyperTextTransferProtocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议。
张炳
2019/08/02
3.8K0
谈谈HTTP1.0,HTTP1.1和HTTP2.0区别
HTTP - HTTP/2 知识点
在《图解HTTP》的读书笔记[《图解HTTP》- HTTP协议历史发展(重点)]当中介绍了一部分关于HTTP/2的内容,但是内容比较简短没有过多深入,本文对于HTTP/2 协议做一个更深入的介绍。
阿东
2022/10/20
1.7K2
HTTP - HTTP/2 知识点
HTTP探索之路 - HTTP 1 / HTTP 2 / QUIC
从1989年万维网(www)诞生,HTTP(HyperText Transfer Protocol)经历了众多版本迭代,WebSocket也在期间萌芽。1991年HTTP/0.9被发明;1996年出现了HTTP/1.0;2015年HTTP/2正式发布;2020年HTTP/3或能正式使用。以下将会简单介绍。 一、HTTP 1.1 与 HTTP 2 1.1 HTTP 1.1 的缺陷 高延迟 — 队头阻塞(Head-Of-Line Blocking) 无状态特性 — 阻碍交互 明文传输 — 不安全
用户1097444
2022/06/29
8330
HTTP探索之路 - HTTP 1 / HTTP 2 / QUIC
Http/2.0
http2.0是一种安全高效的下一代http传输协议。安全是因为http2.0建立在https协议的基础上,高效是因为它是通过二进制分帧来进行数据传输。正因为这些特性,http2.0协议也在被越来越多的网站支持。据统计,截止至2018年8月,已经有27.9%的网站支持http2.0。
大公爵
2022/11/02
1.1K0
Http/2.0
相关推荐
04 网络面经:HTTP 2.0的这些新特性,是时候了解一下了
更多 >
LV.0
阿里巴巴技术专家
目录
  • 前言
  • 程序代码
  • 数据结构与函数详解
  • htons/ntohs
  • inet_pton/inet_ntop
  • sockaddr_in
  • socket--确定协议族和套接字类型
  • bind--指定套接字地址信息
  • listen--监听客户端连接
  • connect--建立连接
  • accept--接受来自客户端的连接
  • 再看echo程序
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档