网络编程(二)—— socket套接字和地址

在这里插入图片描述

文章目录

??什么是socket???

在网络编程中经常跟socket这个单词打交道,译为 “插座、插口”,而我们常称为”套接字“

联想现实生活中的插座、插口,如电脑的USB接口,其作用就是作为两个对象之间的数据收发或能量传递;同理,在网络编程中,socket就是通过插口接入的方式,快速的完成网络连接以及数据的收发。

在这里插入图片描述

上图是网络编程中,TCP客户端和服务器工作的核心逻辑。

网络编程中的基本流程:

  1. 在客户端发起连接请求前,服务器端先初始化
    1. 初始化socket
    2. 执行bind函数,将服务能力绑定在已知的地址和端口
    3. 执行listen函数,将基础socket转换为服务器端特有的socket
    4. 完成上述三个步骤后,阻塞在accept函数上,等待客户端发起连接请求
  2. 待服务器端初始化完成后,客户端发起连接请求
    1. 初始化socket
    2. 执行connect函数向服务器端的地址和端口发起连接请求
  3. 完成上述两个步骤后,此时客户端和服务器端已完成连接的建立,开始传输数据 注意:一旦连接建立,数据的传输就不是单向的,而是双向的,这是TCP特点之一
    1. 客户端进程向操作系统内核申请write字节流操作,将字节流通过网络设备传输到服务器端
    2. 服务器端从内核得到信息,将字节流从内核读入到进程中,开始后续的处理,完成后以同样方式将结果返回客户端
  4. 当客户端和服务器端完成交互动作后,需要和服务器端断开连接时,就需要执行close函数
    1. 系统内核通过原先的连接链路向服务器端发送一个FIN包,服务器收到后执行_被动关闭_,然后执行close函数
    2. 服务器端发送的FIN包没有被客户端接收到时,原先的连接仍是正常的,还可以继续进行数据的发送,只有在接收到FIN包时,整个链路才会完全关闭

上面四个步骤中的前两个步骤,就是平时常说的TCP三次握手。在这一系列的操作中,都始终通过一个媒介进行交流,就是socket。

??通俗的解释socket??

在这里插入图片描述

关于TCP网络交互以及数据传输的流程,大家通常都比喻为打电话,顺着这个思路,代入场景进行联想,就可以很好的从平常生活体验中理解网络编程

记住上面的核心逻辑图,按照上述的网络编程基本流程进行沉浸式代入理解

  1. 服务器端先初始化
    1. socket函数:我们手里的手机
    2. bind函数:比作我们去办一张手机卡,将手机卡插入到手机中,使得这个手机卡和手机绑定在一起,这样别人就可以通过这个号码,找到拿着这个手机的我们
    3. listen函数:就像我们手机电话铃声响起,知道有人给我们打电话这个信息
    4. accept函数:我们拿起手机,点击接听后,等待对方的消息
  2. 客户端初始化
    1. socket函数:别人的手机
    2. connect函数:别人拿起手机,拨通我们的手机号
  3. 上述两个步骤后,此时连接建立。我们能听到对方说话,对方也能听到我们说话
    1. 客户端write函数:别人发起问候:”你好!是靓仔吗?“
    2. 服务器端read函数:我们听到别人真挚的问候,确认通话正常
    3. 服务器端write函数:我们回到:”是的,我是靓仔。有事请说……“
    4. 客户端read函数:别人接收到我们的回复,确认通话正常
    5. 客户端write函数:别人:”下面我要通知你的是恭喜你完成四级英语考试,成绩为424分……“
    6. ……
  4. 当别人事情交待完成后,要结束本次通话了
    1. 客户端close函数:别人:”这是我要说的所有事了,如果你没有事了,我们就结束此次通话吧!“,此时状态为等待挂断(别人没听到我们的回复前,不确定我们是否还有事,所以会处于等待关闭状态)
    2. 服务器端close函数:我们:”我这边没有什么事了,谢谢你的告知!“,挂断了电话。此时我们是已经挂断了电话,通话处于半关闭状态
    3. 客户端:接收到我们的挂断信息后,别人也挂断了电话。本次通话结束

在整个通话过程中,手机(socket)是我们交流的工具,这就是socket的作用。

??套接字地址格式??

什么是套接字地址?在前面我们说到了,网络通信的关键在于使用socket建立连接,而连接的基础是双方地址已知,否则就会导致无头苍蝇到处飞。套接字地址就是前面通俗解释中所说的bind()函数中的电话卡操作,而现实中电话又分两种模式:1. 常用手机电话(如16866666666);2. 固定电话(如(010)123456)

网络编程中,套接字地址格式通常分为三类:

  1. AF_LOCAL:本地地址,对应Unix套接字,由名字可知常用于本地socket通信
  2. AF_INET:互联网常用的IPv4地址格式
  3. AF_INET6:为解决IPv4地址数量不足而新增的IPv6地址格式

上面三种套接字类型中都含有一个共同点:”AF_“,AF其实是 “Address Family” 的英文单词缩写,译为地址族;还有一种网络编程中常见的族:”PF”,即“Protocol Family”,译为协议族。通常AF用于初始化socket地址,PF用于初始化scoket。通过<sys/socket.h>头文件,可以找到各种地址族的宏定义

/* Macro definitions of various address families  */
#define AF_UNSPEC PF_UNSPEC
#define AF_LOCAL  PF_LOCAL
#define AF_UNIX   PF_UNIX
#define AF_FILE   PF_FILE
#define AF_INET   PF_INET
#define AF_AX25   PF_AX25
#define AF_IPX    PF_IPX
#define AF_APPLETALK  PF_APPLETALK
#define AF_NETROM PF_NETROM
#define AF_BRIDGE PF_BRIDGE
#define AF_ATMPVC PF_ATMPVC
#define AF_X25    PF_X25
#define AF_INET6  PF_INET6

??IPv4??

/* IPV4套接字地址,32bit值.  */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };
  
/* 描述IPV4的套接字地址格式  */
struct sockaddr_in
  {
    sa_family_t sin_family; /* 16-bit */
    in_port_t sin_port;     /* 端口号  16-bit*/
    struct in_addr sin_addr;    /* Internet address. 32-bit */


    /* 这里仅仅用作占位符,不做实际用处  */
    unsigned char sin_zero[8];
  };

上面是IPv4套接字地址格式的结构体定义。

  1. 16 bit的 sin_family 字段:IPv4中就是前面所说的AF_INET
  2. 16 bit的 sin_port 字段:支持最大2^16次方个数的端口号,即每个地址最多可有65536个端口号
  3. 32 bit的 sin_addr 字段:最多支持2^32次方(约为42亿)个ip地址,这是一个非常大的数量,但是对于全球来说,显然不够,所以就有了IPv6的设计(注意该字段中的类型还有结构体定义)

小问题:端口号中所有端口都可以随意使用吗?

不是的,上一节知识里有提到过一个知识点——众所周知的端口号。在这里解释一下什么是众所周知的端口号,其实就是互联网发展初期,大家约定好用于某些途径一定会占用的端口号,已经被对应服务广为使用,其他人不能在随意使用这些端口号。具体有哪些保留端口可以百度一下保留端口

??IPv6??

struct sockaddr_in6
  {
    sa_family_t sin6_family; /* 16-bit */
    in_port_t sin6_port;  /* 传输端口号 # 16-bit */
    uint32_t sin6_flowinfo; /* IPv6流控信息 32-bit*/
    struct in6_addr sin6_addr;  /* IPv6地址128-bit */
    uint32_t sin6_scope_id; /* IPv6域ID 32-bit */
  };

上面是IPv6套接字地址格式的结构体定义。

  1. 16 bit的 sin_family 字段:IPv6中即为AF_INET6
  2. 16 bit 的 sinz-port 字段 :与IPv4中定义的范围一样
  3. 32 bit的流控信息字段 :该字段暂时未用到
  4. 128 bit的 sin6_addr 字段:相比IPv4的32 bit,IPv6的 地址字段增大到了 128 bit,这就解决了IPv4地址数量不足的问题
  5. 32 bit的域ID字段 :该字段暂时未用到

??本地套接字地址??

struct sockaddr_un {
    unsigned short sun_family; /* 固定为 AF_LOCAL */
    char sun_path[108];   /* 路径名 */
};

上面是AF_LOCAL的地址格式结构体定义。

  1. sun-family:固定为AF_LOCAL地址族
  2. sun_path :最长108字节的 路径地址

从第二个字段就可以看出这是一个用于本地进程间通信的地址格式,直接通过本地文件路径进行通信

??总结??

  1. socket 是我们用来建立连接,传输数据的唯一途径
  2. 网络通信就需要用到地址族和地址,地址族用于双方约定的格式,地址用于双方寻址。对远程网络通信而言,只知道地址还不行,还需要用到端口来锁定唯一的目标;对于本地通信,文件路径即决定了唯一的目标,所以IPv4/IPv6需要用到端口号,而本地套接字不需要用到端口号
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在Linux网络编程中,TCP客户端编程的流程类似于打电话的过程。首先需要创建一个用于网络通信的socket套接字,通过调用socket()函数来实现。在创建套接字时,需要指定协议类型为IPv4(AF_INET)和数据流类型为TCP(SOCK_STREAM)。函数的返回值是一个套接字描述符,用于后续的通信操作。\[2\] 接下来,需要连接到服务器端,即拨通对方的号码并确定对方是自己要找的人。通过调用connect()函数来实现。在connect()函数中,需要指定服务器IP地址和端口号。如果连接成功,就可以开始进行数据的发送和接收。\[2\] 在TCP客户端编程中,还可以使用send()或write()函数来主动发送数据,使用recv()或read()函数来接收对方的回话。发送和接收的具体实现可以根据实际需求进行调整。\[2\] 最后,在通信结束后,需要调用close()函数来关闭套接字,类似于双方说再见挂电话的过程。这样可以释放资源并结束通信。\[2\] 在网络编程中,还需要使用结构体来表示网络地址。在Linux中,常用的网络地址结构体是sockaddr_in。该结构体包含了网络协议类型、端口号、目的地址等信息。\[1\]\[3\] 总结起来,TCP客户端编程的流程包括创建套接字、连接服务器、发送和接收数据以及关闭套接字。在实际编程中,需要使用socket()、connect()、send()、recv()和close()等函数来完成这些操作。同时,还需要使用sockaddr_in结构体来表示网络地址。 #### 引用[.reference_title] - *1* *2* [Linux 网络编程——TCP编程](https://blog.csdn.net/tennysonsky/article/details/45599027)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Linux 网络编程——TCP](https://blog.csdn.net/fansongy/article/details/6778186)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值