网络套接字

网络套接字

一、认识端口号

​ 在网络通信的时候实际上是两个进程之间的通信(用户使用应用软件的通信)+机器的通信(保证数据安全可靠的送到远端机器);

​ 网络通信的本质就是:进程间的通信+贯穿协议栈+不断封装和解包;

​ 不同主机上的两个进程通信,要看到同一份资源,这个资源就是网络;多进程使用网络协议栈(各种系统用调用)看到了共同的资源

​ 传输层向上给应用层发数据需要进行数据分用,使用端口号交给具体的进程;每一个进程要进行网络通信需要先绑定端口号,发送请求时会添加包含源端口号和目的端口号的报头,便于报文准确的被接收并且返回;

​ 端口号能唯一的标识该主机上的一个网络应用层的进程;

端口号是一个2字节16位的整数;端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;一个端口号只能被一个进程占用;

​ **使用IP:port可以标识全网唯一的一个进程;**这种方式叫做套接字socket;网络单独设计端口不使用pid是因为1.并不是所有的进程都要网络通信,所以直接使用pid表示网络进程的唯一性是不合适的;2.都使用pid导致耦合度过高,使得可维护性较低;

​ 在传输层添加源端口号和目的端口号报头,使得报文可以被准确接受和返回;具体的接受过程类似哈希表的方式,哈希表内部存放的是task_struct的指针,将端口号整数进行哈希运算找到一个位置,此位置没有被使用就直接就将进程的task_struct地址放到此位置,这样就使得通过端口号找到了进程,当然也要保证不能哈希冲突;

​ **以进程看待网络,实际上将网络看作是一个文件,通过文件缓冲区进行数据读写,**TCP便是这样;bind的过程其实就是就是将进程的pcb和系统的哈希表关联起来;

​ 每一个服务的端口号必须是众所周知的,比如http的端口是80,https是443;平常安装的客户端软件内置了服务端的端口号;

一个进程可以绑定多个端口号,但是多个进程不能绑定多个端口号,否则就无法标识唯一性了;

二、认识TCP/UDP协议

​ TCP是传输控制协议,UDP叫做用户数据报协议;

​ TCP协议是面向连接的、可靠传输的、面向字节流的传输层协议;面向连接就是在通信前要保证信道是通畅的,即先通畅后通信,通过三次握手保证面向连接这种特点;面向连接也是保证数据可靠性的一种;可靠传输除了面向连接还包括丢包重传、按需到达、流量控制运算控制等;

​ UDP协议是无连接的、不可靠传输、面向数据报的传输层协议;面向数据报和面向字节流是相对的概念;面向数据报是一次性发送一个数据报,要不然就不接收,要不然收到的就是完成的数据报;发送前是不需要建立连接的,直接就发送过去了;另外发送过去的数据报是否是可靠的传输层是不关心的;

​ 可靠传输是要有很大的成本的,不可靠传输就意味着更简单;TCP的可靠性要定出策略保证知道数据是否丢失,还需要保存数据段一直维护起来,当数据丢失时可以重传,还需要知道重传的周期和次数,还需要编序号保证数据不乱序;反正就是TCP保证可靠性要做很多工作;而UDP设计就非常简单;在可靠性要求非常高的场景下需要使用TCP,而UDP在直播这些做信息派发的场景中常见;

三、网络字节序

​ 小端机:低地址存放低位数据,高地址存放高位数据,大端机:低地址存放高位数据,高地址存放低位数据;

​ 大端小端命名来源于吃鸡蛋是从鸡蛋的大端还是小端开始;

​ 在网络通信中,如果机器大小端不同意就会导致数据的收发出现问题;即使是通过协议的方式也无法解决,所以决定网络字节序统一使用大端字节序,这样就解决了网络通信的问题;

​ 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;因此先发出的数据是低地址,后发出的数据是高地址;所以发送数据是要保证数据是大端方式的;

​ 实际应用场景中仅仅是部分字段需要自己转换成大端,其他的部分系统自动转换了;如:IP/port是需要自己转换的;

3.1网络字节序转换接口

​ 系统当中提供了16/32的主机序列和网络序列的转换接口

#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
//其中h为主机,n为网络,l是long表示4字节,s是short表示2字节;

四、socket网络编程接口

#include <sys/types.h>          
#include <sys/socket.h>
int socket(int domain, int type, int protocol);//服务端和客户端创建socket文件描述符
int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);//服务端进行端口号的绑定
int listen(int sockfd, int backlog);//TCP协议服务端进行监听
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//TCP协议服务端进行接受请求
int connect(int sockfd, const struct sockaddr *addr,
                   socklen_t addrlen);//TCP协议客户端进行连接

​ 对于TCPsocket其实就是一个文件描述符;

4.1sockaddr结构

​ 套接字编程种类:

​ 1.域间套接字编程,用于自己本机内的多进程编程,使用路径唯一性标识然后找到同一份资源,以套接字的方式进行通信;

​ 2.原始套接字编程,一般是绕过了传输层,使用网络层或者数据链路层的一些接口编写一些网络工具,如计算机是否接通,网络抓包等;

​ 3.网络套接字编程,使用传输层协议进行用户间的网络通信;

​ 网络接口的设计者并不想创建三种接口,于是除了创建三种套接字结构体还创建了一个统一的结构,最后使用一套接口;换句话说就是将三种套接字进行了抽象统一;

​ 网络通信使用的是sockaddr_in,本地通信使用的是sockaddr_un,这两种结构的共同点是前16位是类型标识符;AF_INET表示的是IPv4网络的意思,AF_UNIX表示域间套接字;上层使用不同的套接字,设置参数,最后传递的时候统一强转成sockaddr结构;套接字接口函数的内部是会对前16位进行判断是AF_INET还是AF_UNIX,这样就保证了执行不同的通信;这样的方式就是多态的思想;

​ 其实用void*也是可以实现这种通用的接口的,但是当时并没有设计出void*,并且语言的发展只能是向前兼容,所以就没有修改;

在这里插入图片描述

  • 44
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值