socket 提供可通信的场所
ip地址 确定唯一的主机
端口号 确定唯一的进程
字节序 数据能够看懂
1. socket 套接字
1982 - Berkeley Software Distributions 操作系统引入了socket作为本地进程之间通信的接口
1986 - Berkeley 扩展了socket 接口,使之支持UNIX 下的TCP/IP 通信
现在很多应用 (FTP, Telnet, etc) 都依赖这一接口
是一个函数接口,会返回文件描述符
不管是TCP还是UDP都要使用它
socket的类型:
流式套接字(SOCK_STREAM)
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。
用于TCP
数据报套接字(SOCK_DGRAM)
提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
用于UDP
原始套接字(SOCK_RAW)
可以对较低层次协议如IP、ICMP直接访问。
2. ip地址
ip地址是在网络中确定唯一一台主机
mac地址是在一个局域网内确定唯一一台主机,每一个网卡在出厂是会分配一个编号,这个编号就称之为mac地址,每一个mac地址占6字节
查询ip地址的命令:
linux: ifconfig
windows: ipconfig
ip地址的分类:
IPV4,占32位,4个字节
IPV6,占128位,16个字节
IPV4地址的表示形式:
点分十进制,例如192.168.50.216,三个点将地址等分成四个部分,每个部分1个字节,每一部分范围都是0-255
注意:点分十进制的形式只是人为了方便识别才这样写的,开发时只需要将32为地址设置即可,不能加点
点分十进制的ip地址本质是一个字符串,32位的ip地址本质是一个无符号的int类型的整形数据
I
PV4地址的分类(基于ipv4地址前八位来分的)
A类 0000 0000 - 0111 1111 0.x.x.x - 127.x.x.x
B类 1000 0000 - 1011 1111 128.x.x.x - 191.x.x.x
C类 1100 0000 - 1101 1111 192.x.x.x - 223.x.x.x
D类 1110 0000 - 1110 1111 224.x.x.x - 239.x.x.x
E类 1111 0000 - 1111 1111 240.x.x.x - 255.x.x.x
特殊的ip地址:
D类ip地址都是组播地址
E类ip地址属于保留测试
127.x.x.x 属于每一台主机的本地地址,主要用于一台主机的多个进程通过套接字通信可以使用这个ip地址
局域网地址:任意一个ip地址都可以通过路由器下分局域网ip地址,为了解决ipv4地址不够用的问题
![](https://i-blog.csdnimg.cn/blog_migrate/798283bdaba3f3fd63c1bf98caa489d2.png)
ipv4的C类地址的前24为称为网络号,后8位称为主机号
任意一个网段的ip地址中也有一些特殊的ip地址:
拿192.168.50网段举例
192.168.50.0 表示网络号,或者网段
192.168.50.255 表示当前网段下的广播地址
192.168.50.1 表示网关,是路由器的ip地址
理论上一个网段最后可以分配256个ip地址,但是实际只能连接254个
子网掩码:用于判断一个网段下能够连接主机的个数
子网掩码也是32位,每一位与ipv4的地址对应,子网掩码一般是由连续个1和连续个0组成,连续个1对应的ip地址的对应位置称之为网络号,连续个0对应的ip地址的对应位置称之为主机号,所以理论上有多少个0就可以判断连接的主机数
A类ip地址的子网掩码为 255.0.0.0
B类ip地址的子网掩码为 255.255.0.0
C类ip地址的子网掩码为 255.255.255.0
练习题:192.168.50网段下的子网掩码是255.255.255.128,
请问实际连接的主机数是 2^7 - 2 = 126 ,
范围是 192.168.50.129 - 192.168.50.254
地址转换函数:
主要指点分十进制ip地址和无符号32为int类型的ip地址之间的转换
![](https://i-blog.csdnimg.cn/blog_migrate/af25b691140b76c039d68d8e7582a3da.png)
这个转化过程不需要自己实现,有专门的函数已经实现好了:inet_addr inet_ntoa
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//将点分十进制ip地址转化为无符号32位整形数据
in_addr_t inet_addr(const char *cp);
//将无符号32位整形数据转化为点分十进制ip地址
char *inet_ntoa(struct in_addr in);
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char const *argv[])
{
char ip_str[] = "192.168.50.216";
unsigned int ip_int;
ip_int = inet_addr(ip_str);
printf("ip_str = %s\n", ip_str);
printf("ip_int = %u\n", ip_int);
printf("ip_int = %#x\n", ip_int);
unsigned char *p = (unsigned char *)&ip_int;
printf("%d.%d.%d.%d\n", *p, *(p+1), *(p+2), *(p+3));
return 0;
}
3. 端口号
端口号是人为设置的用来区分一个操作系统中进程的编号,一个端口号标识一台主机的唯一一个进程
端口号一般由IANA (Internet Assigned Numbers Authority) 管理
众所周知端口:1~1023(1~255之间为众所周知端口,256~1023端口通常由UNIX系统占用)
已登记端口:1024~49151
动态或私有端口:49152~65535
可以使用vi /etc/services 查看已经被占用的端口号,一般我们可以使用6666、7777、8888、9999、10000、10001都可以用
4. 字节序
不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO):
小端序(little-endian) - 低序字节存储在低地址
将低字节存储在起始地址,称为“Little-Endian”字节序,Intel、AMD等采用的是这种方式;
大端序(big-endian)- 高序字节存储在低地址
将高字节存储在起始地址,称为“Big-Endian”字节序,由ARM、Motorola等所采用
![](https://i-blog.csdnimg.cn/blog_migrate/a2d9e5ba85d8dcdc0ab58f897cbab1b8.png)
如何测试主机字节序:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int a = 0x12345678;
char *p = (char *)&a;
printf("*p = %#x\n", *p);
if(*p == 0x78)
{
printf("小端存储\n");
}
else
{
printf("大端存储\n");
}
return 0;
}
如果两个主机之间想要通信,那么还需要确定两个主机的字节序是否一样,如果不一样,收发的数据可以会出问题
网络中传输的数据必须按网络字节序,即大端字节序
例如:张三要给李四发送数据,张三就需要将数据从主机字节序转化为网络字节序,李四接收到数据之后,将网络字节序的数据转化为主机字节序,这样就保证数据传输无误
什么样的数据在传输的时候需要考虑字节序?
如果是单个字符或者字符串,是不需要考虑字节序的,因为一个字节一个字节存取时不涉及字节序的转换
如果多个字节作为一个整体,就需要考虑字节序,比如端口号
具体主机字节序与网络字节序之间的转换不需要自己实现,有专门的函数
htons htonl ntohs ntohl
#include <arpa/inet.h>
将主机字节序转化为网络字节序
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
将网络字节序转换为主机字节序
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
#include <stdio.h>
#include <arpa/inet.h>
int main(int argc, char const *argv[])
{
unsigned int a = 0x12345678;
unsigned int b = htonl(a);
printf("a = %#x\n", a);
printf("b = %#x\n", b);
return 0;
}
执行结果
![](https://i-blog.csdnimg.cn/blog_migrate/a693a477a8c824ffeefc7d559f836db8.png)