Linux网络编程
1.TCP/UDP对比
TCP | UDP |
---|---|
TCP面向连接(如打电话要先拨号建立连接) | UDP是无连接的,即发送数据之前不需要建立连接 |
TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达 | UDP尽最大努力交付,即不保证可靠交付 |
TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流 | UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等) |
每一条TCP连接只能是点到点的; | UDP支持一对一,一对多,多对一和多对多的交互通信 |
TCP首部开销20字节 | UDP的首部开销小,只有8个字节 |
TCP的逻辑通信信道是全双工的可靠信道 | UDP则是不可靠信道 |
2.端口号作用
一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等。
这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP 地址与网络服务的关系是一对多的关系。
实际上是通过“IP地址+端口号”来区 分不同的服务的。端口提供了一种访问通道,服务器一般都是通过知名端口号来识别的。例如,对于每个TCP/IP实现来说,FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69。
3.字节序
字节序(Byte Order)是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
在计算机中是以字节为单位,每个地址对应一个字节,一个字节8bit。在C中,除了8bit的char以外,还有16bit的short,32位的int,64位long,当然具体要由编译器决定,可以通过sizeof来获取不同类型在内存中占用的字节数。
在计算机系统中,当物理单位的长度大于1个字节时,就要区分字节顺序。
常见的字节顺序有两种:大端(Big-endian)和小端(Little-endian),当然还有其他字节顺序,但不常见,例如Middle Endian。
1.高低字节
在一个n进制的位中,最左边的位叫最高有效位,最右边的叫最低有效位。
举个例子,1个int的整数123456789
二进制表示 | 0000 | 0111 | 0101 | 1011 | 1100 | 1101 | 0001 | 0101 |
---|---|---|---|---|---|---|---|---|
十六进制表示 | 0 | 7 | 5 | B | C | D | 1 | 5 |
按照从右向左的方向,二进制中,0101是低字节,最左边的0000是高字节;十六进制中,15是低字节,07是高字节。
再通俗一点解释就是:8421码的,8这端为高位,1这端为低位,相应的字节则分别称为高位字节和低位字节。
2.高低地址
在内存中,多字节对象都是被存储为连续的字节序列。假设将int整型在内存中的起始地址(首个字节存储位置)为0x1000,那么另外三个字节就存储在0x1001~0x1003。不管存储的字节顺序是怎样的,内存地址的分配都是从小到大的增长。其中0x1000称为低地址端,0x1003称为高地址端。
3.大端和小端
大端:高字节存放在低地址。
小端:低字节存放在低地址。
还是以上面的int 123456789为例,十六进制表示: 07 5B CD 15
内存地址(低——>高) | 字节存储顺序 | ||
---|---|---|---|
大端(Big Endian) | 0x1000 0x1001 0x1002 0x1003 | 0x07 0x5B 0xCD 0x15 | 高字节存放在低地址 低字节存放在高地址 |
小端(Litter Endian) | 0x1000 0x1001 0x1002 0x1003 | 0x15 0xCD 0x5B 0x07 | 低字节存放在低地址 高字节存放在高地址 |
4.网络字节序和主机字节序
大小端一般是由CPU架构决定的。
- 网络字节序(Network Order):TCP/IP各层协议将字节序定义为Big Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
- 主机字节序(Host Order):整数在内存中保存的顺序,它遵循Little Endian规则(不一定,要看主机的CPU架构)。所以当两台主机之间要通过TCP/IP协议进行通信的时候就需要调用相应的函数进行主机序列(Little Endian)和网络序(Big Endian)的转换。
1、网络协议指定了通讯字节序—大端(网络字节序 = 大端)
2、只有在多字节数据作为整体处理时才需要考虑字节序
3、运行在同一台计算机上的进程相互通信时,一般不用考虑字节序
4、异构计算机之间通讯,需要转换自己的字节序为网络字节序
冷知识:x86 系列 CPU 都是 little - endian 的字节序
为什么不统一使用一种字节序?
- 计算机电路先处理低位字节,效率比较高。因为计算就是从低位开始的,所以计算机内部很多都是小端字节序。
- 格式规范是为人类编写的,大端字节序更符合人类习惯。
5.字节序转换API
#include <netinet/in.h>
//htons函数 发 将主机字节序的端口 转换成 网络字节序的端口
uint16_t htons(uint16_t host16bitvalue); //返回网络字节序的值
//htonl函数 发 将主机字节序的IP地址 转换成网络字节序的IP地址
uint32_t htonl(uint32_t host32bitvalue); //返回网络字节序的值
//ntohs函数 收 将网络字节序的端口 转换成 主机字节序的端口
uint16_t ntohs(uint16_t net16bitvalue); //返回主机字节序的值
//ntohl函数 收 将网络字节序的IP地址
uint32_t ntohl(uint32_t net32bitvalue); //返回主机字节序的值
- h代表host,n代表net,s代表short(两个字节),l代表long(4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取
- htons htonl ntohs ntohl 如果主机 和网络 字节序相同 前面4个函数不会颠倒数据
htons htonl ntohs ntohl 如果主机 和网络 字节序 不相同 前面4个函数会颠倒数据
大小端 不是人为决定的
6.地址转换API
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char* straddr,struct in_addr *addrp);//把字符串形式的“192.168.1.123”转为网络能识别的格式
char* inet_ntoa(struct in_addr inaddr); //把网络格式的ip地址转为字符串形式
int inet_aton(const char* cp, struct in_addr* inp);//点分十进制的ip地址转换成网络字节序的ip地址
in_addr_t inet_addr(const char* cp);//点分十进制的ip地址转换成32位整数
char* inet_ntoa(struct in_addr in);//32位整数转换成点分十进制的ip地址
4.套接字
1.概念
socket,即套接字是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行。也就是说它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。也因为这样,套接字明确地将客户端和服务器区分开来。
2.属性
套接字的特性由3个属性确定,它们分别是:域、类型和协议。
-
套接字的域
它指定套接字通信中使用的网络介质,最常见的套接字域是AF_INET,它指的是Internet网络。当客户使用套接字进行跨网络的连接时,它就需要用到服务器计算机的IP地址和端口来指定一台联网机器上的某个特定服务,所以在使用socket作为通信的终点,服务器应用程序必须在开始通信之前绑定一个端口,服务器在指定的端口等待客户的连接。另一个域AF_UNIX表示UNIX文件系统,它就是文件输入/输出,而它的地址就是文件名。
-
套接字类型
因特网提供了两种通信机制:流(stream)和数据报(datagram),因而套接字的类型也就分为流套接字和数据报套接字。这里主要讲流套接字。
流(stream)TCP 和数据报(datagram)UDP
流套接字由类型SOCK_STREAM指定,它们是在AF_INET域中通过TCP/IP连接实现,同时也是AF_UNIX中常用的套接字类型。流套接字提供的是一个有序、可靠、双向字节流的连接,因此发送的数据可以确保不会丢失、重复或乱序到达,而且它还有一定的出错后重新发送的机制。
与流套接字相对的是由类型SOCK_DGRAM指定的数据报套接字,它不需要建立连接和维持一个连接,它们在AF_INET中通常是通过UDP/IP协议实现的。它对可以发送的数据的长度有限制,数据报作为一个单独的网络消息被传输,它可能会丢失、复制或错乱到达,UDP不是一个可靠的协议,但是它的速度比较高,因为它并一需要总是要建立和维持一个连接。
-
套接字协议
只要底层的传输机制允许不止一个协议来提供要求的套接字类型,我们就可以为套接字选择一个特定的协议。通常只需要使用默认值。
3.Sockt服务器和客户端的开发步骤
我是服务器是说汉语(TCP/UDP)我ip地址(楼号)是 。。我端口号(房间号)是。。我在监听(等待大家的来访,来了敲门
整体思路:
1.创建套接字
2.为套接字添加信息(IP地址和端口号)
3.监听网络连接
4.监听到有客户端接入,接受一个连接
5.数据交互
6.关闭套接字,断开连接
1、创建套接字socket
服务端
指定讲“汉语”(连接协议)
//该函数用来创建一个套接字,并返回一个描述符,该描述符可以用来访问该套接字,它的原型如下:
#include