【网络】socket套接字

1.理解IP

每台主机都有自己的IP地址,所以当数据从一台主机传输到另一台主机就需要IP地址。报头中就会包含源IP和目的IP。源IP地址:发送数据报那个主机的IP地址,目的IP地址:想发送到的那个主机的IP地址我们把数据从一台主机传递到另一台主机不是真正目的,真正通信的不是这两个机器,通信的主体是两个主机上的进程。但是一个主机上有很多的进程,公网IP虽然标识了一台唯一的主机,那么数据就可以由一台主机传递到另一台主机,但是两个主机上的进程有很多,怎么保证主机A上的进程a和主机B上的进程b通信呢?也就是说用什么来标识主机上客户或者服务进程的唯一性是关键的,为了更好的表示一台主机上服务进程的唯一性,用端口号port标识服务进程、客户端进程的唯一性。

2.端口号

端口号 (port) 是传输层协议的内容:
 -- 端口号是一个 2 字节 16 位的整数 ;
 -- 端口号用来标识一个进程 , 告诉操作系统 , 当前的这个数据要交给哪一个进程来处理 ;
 -- IP 地址 + 端口号能够标识网络上的某一台主机的某一个进程 ;
 -- 一个端口号只能被一个进程占用但是一个进程可以绑定多个端口号

网络通信的本质就是进程间通信,进程间通信的本质是看到同一份资源,现在这个资源就是网络,通信的本质就是IO,因为我们上网的行为就两种情况:接收数据和发送数据

IP标定主机唯一性,port 标定进程唯一性 ----> IP+port   ==   进程在全网的唯一性

思考:进程在主机上可以用pid标识唯一性,那网络通信为什么不用IP+pid锁定要通信的进程呢?

原因:

pid是系统规定的,而port是网络规定的,这样就可以把系统和网络解耦
port标识服务器的唯一性不能做任何改变,要让客户端能找到服务器而每次启动进程pid就会改变。
不是所有的进程都需要网络通信即不是所有的进程都拥有端口号,但每个进程都需要pid。
 

3.认识 tcp / udp 协议

TCP(Transmission Control Protocol 传输控制协议) 特点:

传输层协议
有连接(正式通信前要先建立连接)
可靠传输(在内部帮我们做可靠传输工作)
面向字节流

UDP(User Datagram Protocol 用户数据报协议) 特点:
传输层协议
无连接
不可靠传输
面向数据报

理解不可靠传输:如发送数据时出现了丢包的情况、或者数据被重复传递了或者网络出现了问题等等造成的后果就叫做不可靠。所以传输层就是用来解决可靠性的一个协议。可不可靠是一个中性词。可靠是需要成本的,往往在维护和编码上都比较复杂;而不可靠没有成本,使用起来也简单。所以要分场景使用。

4.网络字节流

我们已经知道 , 内存中的多字节数据相对于内存地址有大端和小端之分。
大端存储: 低权值的数放入低地址。
小端存储: 低权值的数放入高地址。
这样就有可能一个大端机用大端的方式发送数据到一个小端机。如果现在跨网络我们也不知道数据到底是大端和小端,会导致接收到的数据被解析为了别的意思,所以规定: 网络中的数据都是大端发送数据的主机如果是大端机就不用管如果是小端机就把发送的数据由小端转为大端再发送,接收数据同理。

发送主机把发送缓冲区中的数据按内存地址从低到高的顺序发出
接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存

也就是说先发出的数据是低地址,后发出的数据是高地址

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可。

调用库函数做网络字节序和主机字节序的转换:
#include <arpa/inet.h>

// 主机序列转网络序列
uint16_t htons(uint16_t hostshort);
uint32_t htonl(uint32_t hostlong);

// 网络序列转主机序列
uint16_t ntohs(uint16_t netshort);
uint32_t ntohl(uint32_t netlong);
h表示host,n表示network,l表示32位长整数,s表示16位短整数。主机是大端还是小端在函数内部会自己进行判断。

5.socket套接字接口

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);

// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);

// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);

// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);

// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

ip和端口号port就叫为套接字,socket就是插座的意思,未来进行网络通信时,插头和插座配套使用。

常见套接字的种类1.网络套接字2.原始套接字3.unix域间套接字

网络套接字主要运用于跨主机之间的通信,也能支持本地通信,而域间套接字只能在本地通信。而原始套接字可以跨过传输层(TCP/IP协议)访问底层的数据。这些套接字应用场景完全不同,所以我们想用就得用三套不同的接口。而为了方便,设计者只设计了一套接口,就可以通过不同的参数,解决所有网络或者其他场景下的通信问题。

struct sockaddr_in {
    short int sin_family;           // 地址族,一般为AF_INET
    unsigned short int sin_port;    // 端口号,网络字节序
    struct in_addr sin_addr;        // IP地址
    unsigned char sin_zero[8];      // 用于填充,使sizeof(sockaddr_in)等于16
};

struct sockaddr_un {
    sa_family_t sun_family;       /* AF_UNIX */
    char sun_path[108];    /* 带有路径的文件名 */
};//通过同一个文件的路径来让进程看到同一份资源

 

可以看到sockaddr_in和sockaddr_un是两个不同的通信场景。区分它们就用前2个字节:16地址类型协议家族的标识符(代表是本地通信还是网络通信)。 我们两个结构体都不用用的是sockaddr。未来进行网络编程时,如果是网络通信,填充的网络信息是struct sockaddr_in这个结构体。所以这就相当于:可以把 sockaddr看成基类,把 sockaddr_insockaddr_un看成派生类,构成了多态体系。 sockaddr使用统一的接口解决所有网络或者其他场景下的通信问题。
  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bite-ccc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值