linux网络(3)—— socket编程(1)socket基础认识

欢迎来到博主的专栏:linux网络
博主ID:代码小豪

IP与端口号

我们现在知道了,只要发送的报文的报头包含目的IP地址和源IP地址,就能通过通信设备,是两台主机进行远程通信,但是问题来了,当数据到达主机后,这个数据该如何使用?

比如现在小王的主机正在下载游戏,并且使用qq在和同学聊天,那么在小王的主机中就会存在两股数据流,分别是下载的数据流和qq的数据流,那么当数据流到达主机后,如何分辨哪些是给qq的,还是给下载游戏的呢?

首先在小王的主机中运行着两个进程,一个是下载器(WeGame或者steam),还有一个是qq,只要把数据流交给给进程处理,那么这两个数据流就相当于被正确的使用了。因此,在网络当中一定存在一个标识主机的进程的唯一标识码,这个标识码就叫做端口号。
在这里插入图片描述

端口号是一个16位的无符号整数,一个端口号可以标识一个进程,其中0~1023的端口号是固定的,用来标识如http,ssh,ftp等端口号。而1024~65535的端口号则用来标识用户的客户端程序,即进程。

因此在UDP和TCP协议的报头,会保存目的主机的IP地址和端口号这样就能保证数据准确的来到目的主机,以及目的主机中的正确的进程。

综上,IP 地址用来标识互联网中唯一的一台主机,port 用来标识该主机上唯一的一个网络进程,IP+Port 就能表示互联网中唯一的一个进程所以,通信的时候,本质是两个互联网进程进行通信,所以网络通信的本质,是进程间通信,只是这两个进程不在同一台主机当中。

socket

socket=IP地址+端口号。socket可以看做是一个接口,或者是一个对象,这个对象可以完成网络通信,其主要的成员是源IP地址+源端口号(发送数据的主机和进程),以及目的IP地址+目的端口号(接收数据的主机+进程)。

根据网络协议的不同,socket分为TCP socket和UDP socket,其两者的不同之处如下图:

1.TCP socket:基于TCP协议的socket,其提供可靠的,面相字节流的传输。
2.UDP socket:基于UDP协议的socket,其提供不可靠的,面相数据包的传输。

使用socket需要用上与socket相关的API,博主这里只展示,不讲解,在后续的博客中会结合实例讲解这些API。

// 创建 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 connect(int sockfd, const struct sockaddr *addr,socklen t addrlen);

socketaddr分为三种,其代表socket对象的三种格式,分别是struct sockaddr,struct sockaddr_in,struct sockaddr_un。其代表三种形式的socket,分别是原始socket,网络通信的socket,本地通信的socket。由于这三种socket的使用场景不同,因此它们的结构也不相同。

在这里插入图片描述

那么在socket API当中,用来描述socket的类型通常都是struct sockaddr*,而我们在编程当中大多会使用struct sockaddr_in来进行网络通信的套接字,或者struct sockaddr_unix作为本地通信的套接字,因此需要通过类型强制转换,将上述的类型转换成struct sockaddr*。才能正确的使用socket API。

字节序问题

现在的主流的主机如x86,x64,采用的字节序都是小端字节序存储,但是世界上并非不存在大端字节序存储的主机,因此在网络通信方面。小端机器上的数据存储形式和大端机器上的数据存储形式可能是不同的。因此相同的二进制数据,需要进行大小端的转换,才能被主机正确的解码。

根据协议规定,在网络上的数据的字节序,一律采取大端的存储形式,因此如果是小端机器要将数据转发到网络,首先要将数据从小端转换为大端,然后如果接收数据的主机如果是小端,那么又要将网络当中的数据,从小端转换到大端。

但是我们发送数据的主机,可能是大端,也可能是小端,而接收数据的主机,也可能是大端,或者小端,因此在客户端/服务器的程序当中,直接强制规定将数据从小端转成大端,或者将小端转换成大端的方式并不明智,因为如果运行客户端的是大端,那么程序会失效,服务器也是同理。因此更为正确的做法是:将主机的存储方式(无论大小端),视为主机字节序,而网络的存储形式,视为网络字节序。当数据需要发送到网络时,无论是大小端的机器,都要进行将数据从主机字节序,转换成网络字节序,这里我们通常采用htois,htoil来完成。而数据从网络来到主机时,需要将网络字节序,转换成主机字节序,这个操作有ntohs,ntohl函数来完成。

这样做的好处是,无论是主机是大端小端,都要进行主机字节序转网络字节序这一步操作,如果是小端机器,那么就将数据从小端转成大端,如果是大端机器,那么就不对数据进行处理,反之接收网络的机器的处理方式也是同理,这样就能保证程序的网络通信部分,可以在大端,小端机器上都能正确运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

代码小豪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值