网络编程套接字socket

目录

1、套接字的关键因素

[1.1 端口号](#1.1 端口号)

[1.2 IP地址](#1.2 IP地址)

[1.3 套接字类型](#1.3 套接字类型)

[1.4 套接字常见接口](#1.4 套接字常见接口)

[1.5 套接字种类](#1.5 套接字种类)

2、网络字节序

结语


前言:

网络编程中的套接字(socket)是实现网络通信的关键,换句话来说,套接字像两个端点,而发送方与接收方就是通过这两个端点进行通信的,socket的意思是插座,表示插头和插座连接上后,即发送方和接收方连接上了,然后把电流通过插座流向插头对标发送方与接收方建立了链接。

1、套接字的关键因素

网络通信的本质是进程间通信,只不过这两个进程不在同一个主机上,而socket要让这两个进程进行通信,则socket必须提供某些字段,以便于让这两个进程找到彼此。socket关键字段介绍如下文。

1.1 端口号

端口号属于传输层协议,端口号是一个2字节16bit位的整数 ,他的作用就是找到该主机上的对应进程,并将通信的信息给到该进程。一个进程可以绑定多个端口号,但是一个端口号不能被多个进程绑定,即一个端口号只能对应一个进程。

1.2 IP地址

IP地址是每台主机每台设备在网络中的唯一标识符,通过IP地址就可以在全球网络中定位唯一一台主机或设备。至此,有了端口号和IP地址,就能让发送进程在茫茫的网络中找到接收进程。

示意图如下:

1.3 套接字类型

套接字有两种类型:1、TCP-流式套接字(SOCK_STREAM),2、UDP-数据报套接字(SOCK_DGRAM)。他们都是传输层的协议,在进行通信时,必须对套接字的类型进行定义。

而TCP和UDP的区别在于:TCP较UDP更加"负责",主要体现在TCP收到应用层的报文后,会对这个报文负责到底,如果该报文在后面的过程中发生传输失败或者传输时乱序,则TCP会重新发送一份。

而udp就不一样了,不管这个报文传输成功了还是失败了udp都不会对其维护,udp只负责把从应用层接收到的报文给到下层。

也正是这样,因此TCP的维护成本会更高。

1.4 套接字常见接口

在Linux下使用套接字时,通常会搭配一些常见接口实现通信,接口如下:

cpp 复制代码
// 创建 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);

1.5 套接字种类

上述接口中有一个叫做struct sockaddr的结构类型,他是套接字种类,种类的不同导致使用的网络层协议的不同,比如sockaddr_in用于IPv4,sockaddr_in6用于IPv6。而上述函数中形参默认使用struct sockaddr*类型,目的就是为了程序的通用性,能够接收IPv4或IPv6以及其他类型的套接字种类。简单来说就是用IPv4协议,则需要定义sockaddr_in类型的变量,用IPv6则定义sockaddr_in6的变量。

套接字种类示意图:

IPv4、IPv6地址类型分别对应上图的常数AF_INET、AF_INET6。


基于IPv4编程时, 使用的数据结构是sockaddr_in,这个结构体里主要有三个信息是值得关注的:1、地址类型, 2、端口号, 3、IP地址,在定义sockaddr_in变量时,这三个信息需要我们手动填写,然后再调用函数bind进行绑定。

2、网络字节序

内存中的数据相对于内存的地址有大小端之分,小端机器指的是低字节内容存在低地址处,大端机器指的是高字节内容存在低地址处。而网络传输数据时,是先传低地址的内容再传高地址的内容,并且规定采用大端字节序的方式传递数据(即使是在小端机器上),所以接收方默认接收的字节是高字节内容,因此如果当前发送主机是小端, 就需要先将数据转成大端模式再进行发送,若是大端则直接发送即可。


而现实中大部分使用的都是小端机器,若在小端机器上手动把数据转成大端模式,是一件很麻烦的事情,因此在Linux下系统提供了可以帮助我们实现小端转大端的接口,接口如下:

cpp 复制代码
#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);

简单的记忆方法:函数名中以to为分隔,h表示host(主机序列),n表示network(网络序列),l表示long类型,s表示short类型。

比如htonl函数是将32位的长整数从当前主机序列转换为网络序列。如果主机是小端字节序,调用上述函数则转成大端字节序,如果主机是大端字节序,这些函数不做处理直接返回原有值。简单来说,ntohs和ntohl默认形参是大端字节序,而htons和htonl默认返回值是大端字节序。

结语

以上就是关于网络套接字socket的讲解,socket是应用层实现通信的关键因素,发送方和接收方若想实现通信则必须使用socket套接字。

最后如果本文有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!!

相关推荐
我们的五年2 分钟前
【Linux课程学习】:进程描述---PCB(Process Control Block)
linux·运维·c++
qdprobot4 分钟前
ESP32桌面天气摆件加文心一言AI大模型对话Mixly图形化编程STEAM创客教育
网络·人工智能·百度·文心一言·arduino
运维老司机25 分钟前
Jenkins修改LOGO
运维·自动化·jenkins
D-海漠41 分钟前
基础自动化系统的特点
运维·自动化
我言秋日胜春朝★1 小时前
【Linux】进程地址空间
linux·运维·服务器
繁依Fanyi1 小时前
简易安卓句分器实现
java·服务器·开发语言·算法·eclipse
C-cat.1 小时前
Linux|环境变量
linux·运维·服务器
yunfanleo1 小时前
docker run m3e 配置网络,自动重启,GPU等 配置渠道要点
linux·运维·docker
m51271 小时前
LinuxC语言
java·服务器·前端
hakesashou2 小时前
Python中常用的函数介绍
java·网络·python