Linux系统编程之网络编程(socket)

一、socket网络编程
首先简单介绍一下UNIX/Linux下的socket
在UNIX、Linux系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。

你也许听过很多高手说过,UNIX/LLinux中的一切皆文件,那个家伙说的没错。

为了表示和区分已经打开的文件,UNIX/Linux会为每个文件分配一个ID,这个文件就是一个整数,被称为文件描述符(File Descriptor),例如:
通常用 0 来表示标准输入文件(stdin),它对应的硬件设备就是键盘;
通常用 1 来表示标准输出文件(stdout),它对应的硬件设备就是显示器。

UNIX/Linux 程序在执行任何形式的 I/O 操作时,都是在读取或者写入一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数,它的背后可能是一个硬盘上的普通文件、FIFO、管道、终端、键盘、显示器,甚至是一个网络连接。

请注意,网络连接也是一个文件,它也有文件描述符,你必须理解这句话:

我们可以通过 socket() 函数来创建一个网络连接,或者说打开一个网络文件,socket() 的返回值就是文件描述符(注意在windows下的socket返回的叫文件句柄,并不是叫文件描述符)。有了文件描述符,我们就可以使用普通的文件操作函数来传输数据了,例如:
read() 读取从远程计算机传来的数据;
write() 向远程计算机写入数据。

你看,只要用 socket() 创建了连接,剩下的就是文件操作了,网络编程原来就是如此简单!
那么现在我们正式来介绍一下关于socket的相关知识;

1.TCP/UDP的区别
首先标准套接字分为TCP和UDP协议两种不同type的工作流程,TCP网络编程相对于UDP来说相对复杂,因为TCP是面向连接的服务,其中包括三次握手建立连接的过程,而UDP则是无连接的服务。

(1)TCP面向连接(如打电话要先拨号建立连接),而UDP是无连接的,即发送数据之前不需要建立连接。
(2)TCP提供可靠的服务,也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;而UDP则是尽最大努力进行交付,即不保证可靠交付。
(3)TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;而UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(这样对实时应用很有用,如,IP电话,实时视频会议等)。
(4)每一条的TCP只能是点到点的,UDP支持一对一,一对多,多对一和多对多的交互通信
(5)TCP首部开销20字节;UDP首部开销小,只有8个字节。
(6)TCP的逻辑通信的信道是全双工的可靠信道,而UDP则是不可靠信道。

接下来看一下TCP和UDP的两种模式的流程区别
TCP:服务端和客户端的通信流程:
在这里插入图片描述
UDP:服务端和客户端的通信流程:
在这里插入图片描述
由上图可以看出,UDP与TCP的区别是UDP中是少了连接的过程。

2.那么介绍完TCP/UDP后,我们再来看一下IP地址跟端口号
IP地址:IP地址是网络中主机(电脑)的标识,在网络中主机想要与其他机器通信就必须拥有一个自己的IP地址,IP地址为32位(IPV4)或者128位(IPV6),每一个数据包都必须携带目的地址IP和源IP地址,路由器依靠此信息为数据包选择最优路由(路线)。(IP地址就有点像是几栋楼中的楼的号码)

端口号:用于区分一台主机中接收到的数据包应该交给那一个进程进行处理(注意TCP和UDP的端口号是相互独立的)(如果IP地址是相当于一栋楼的楼号的话,那么端口号就相当于是这栋楼里面的房间的房号)

那么来介绍一下端口号的作用是什么;
一台拥有IP地址的主机可以提供许多服务,比如Web服务,FTP服务,SMTP服务等。
这些服务完全是可以由一个IP地址来实现的,那么,主机是怎么样区分不同的网络服务的呢?显然不能只靠IP地址,因为IP地址与网络服务的关系是一对多的关系。

实际上通过"IP地址+端口号"来区分不同的服务的
端口提供了一种访问通道,服务器一般都是通过知名的端口来识别的。例如,对于每个TCP/IP的实现来说,FTP服务的端口号是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69。

3.接下来我们来看一下什么是字节序
字节序:是指多字节数据的存储顺序,在设计计算机系统的时候,有两种处理内存中数据的方法:即大端格式、小端格式。

小端格式(Little-Endian):将低位字节数据存储在低地址。
大端格式(Big-Endian):将高位字节数据存储在低地址。

接下来看一个图就基本理解的了
在这里插入图片描述
接下来就简单的举个例子吧,对于整型的0x12345678,它在大端格式和小端格式中的系统的存储方式如下图所示:
在这里插入图片描述

网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递那个字节呢?也就是说,当接收端接收到第一个字节的时候,它是将这个字节当做低位还是高位来处理呢?

网络字节序的定义:将收到的第一个字节的数据当做高位来看待,这就要求发送端的发送的第一个字节应该是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。

所以,网络协议指定了通讯字节序:大端。只有在多字节数据处理时才需要考虑字节序,运行在同一台计算机上的进程相互通信时,一般不用考虑字节序,异构计算机之间进行通讯时,需要将自己的字节序转换为网络字节序。

那么下面就介绍一下有关字节序转换的函数:
以下所有接口的头文件都是: #include <arpa/inet.h>

函数一:
函数原型:

 uint16_t htons(uint16_t hostshort);

功能:

将16位主机字节序数据转换成网络字节序数据

参数:

hostshort:需要转换的16位主机字节序数据,uint16_t:unsigned short int

返回值:

成功返回网络字节序的值

函数二:
函数原型:

 uint32_t htonl(uint32_t hostlong);

功能:

将32位主机字节序数据转换成网络字节序数据

参数:

hostlong:需要转换的32位主机字节序数据,uint32_t:32位无符号整型

返回值:

成功:返回网络字节序的值

函数三:
函数原型:

uint32_t ntohl(uint32_t netlong);

功能:

将32位网络字节序数据转换成主机字节序数据

参数:

netlong:需要转换的32位网络字节序数据;uint32_t:unsigned int

返回值:

成功:返回主机字节序的值

函数四:
函数原型:

uint16_t ntohs(uint16_t netshort);

功能:

将16位网络字节序数据转换成主机字节序数据

参数:

netshort:需要转换的16位网络字节序数据;uint16_t:unsigned short int

返回值:

成功:返回主机字节序的值

介绍完字节序转换函数后,那么现在我们来看一下地址转换函数:
首先我们先来介绍将字符串形式(即点分十进制)的地址转换成网络能识别的地址格式,
这里有inet_atoninet_pton两个函数

两者的异同:
共同点:两者功能都是将点分十进制的IP地址转换成网络能识别的地址格式(即二进制)
不同点:(1)参数数量不同,使用上有小区别
(2)inet_aton只适用于IPV4地址,inet_pton适用于IPV4和IPV6地址
(3)理论上讲前者是旧函数,后者是新函数

函数一:

int inet_aton(const char *cp, struct in_addr *inp);

功能:

将点分十进制字符串转换成32位无符号整数

参数:

cp:将被转换的点分十进制IP地址
inp:保存被转换成二进制的IP地址

返回值:

如果地址合法,则返回非0值,反之返回0值

函数二
函数原型:

int inet_pton(int af, const char *src, void *dst);

函数描述:

该函数将字符串src转换为af地址类型协议簇的网络地址,并存储到dst中。
对于af参数,必须为AF_INETAF_INET6

功能:

将 IPv4 和 IPv6 地址从点分十进制转换为二进制

参数:

af:AF_INETAF_INET6
src:将被转换的点分十进制的IP地址
dst:保存被转换的二进制IP地址

返回值:

转换成功则返回1,对于指定的地址类型协议簇,如果不是一个有效的网络地址,
将转换失败,返回 0,
如果指定的地址类型协议簇不合法,将返回-1并,并且errno设置为EAFNOSUPPORT

在介绍完点分十进制的IP地址转换成二进制IP地址后,现在我们来介绍一下将二进制IP地址转换成点分十进制的IP地址的函数
这里有inet_ntoainet_ntop两个函数
两者的异同之处如上所示

函数三:
函数原型:

 char *inet_ntoa(struct in_addr in);

函数描述:

inet_ntoa()用来将参数in所指的大端网络字节序二进制的数字转换成ipv4点分十进制字符串网络地址,然后将指向此网络地址字符串的指针返回。成功则返回字符串指针,失败则返回NULL

功能:

将二进制IP地址转换成点分十进制的IP地址

参数:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值