网络编程套接字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套接字。

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

相关推荐
七夜zippoe5 小时前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
盟接之桥5 小时前
盟接之桥说制造:引流品 × 利润品,全球电商平台高效产品组合策略(供讨论)
大数据·linux·服务器·网络·人工智能·制造
会员源码网5 小时前
理财源码开发:单语言深耕还是多语言融合?看完这篇不踩坑
网络·个人开发
米羊1216 小时前
已有安全措施确认(上)
大数据·网络
Fcy6486 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满6 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
代码游侠7 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
主机哥哥7 小时前
阿里云OpenClaw部署全攻略,五种方案助你快速部署!
服务器·阿里云·负载均衡
Harvey9037 小时前
通过 Helm 部署 Nginx 应用的完整标准化步骤
linux·运维·nginx·k8s
ManThink Technology7 小时前
如何使用EBHelper 简化EdgeBus的代码编写?
java·前端·网络