创建套接字
#include<sys/socket.h>
int socket(int domain,int type, int protocol)
成功时返回文件描述符,失败时返回1
domain 套接字中使用的协议族 type 套接字数据传输类型信息 protocol 计算机间通信中使用的协议信息
协议族
PF_INET 对应的IPv4互联网协议族
套接字类型
套接字的类型指的是套接字的数据传输方式,通过socket函数的参数传递,只有这样才能决定创建的传输方式。
1. 面向连接的套接字(SOCK_STREAM)
特定与TCP相同 ,对应TCP连接 可靠的、按序传递的、基于字节的面向连接的数据传输方式的套接字
2. 面向消息的套接字(SOCK_DGRAM)
UDP 不可靠的,不按序传递的,以数据的高速传输为目的的套接字
协议的最终选择
大部分 第三个参数传递0,除非遇到下面这种情况 “同一协议族存在多个数据传输方式相同的协议”
表示 IPv4地址的结构体
struct sockaddr_in{
sa_family_t sin_family; // 地址族(address family)
uint_t sin_port;// 16位TCP/UDP端口号 TCP和UDP的端口号 相互独立
struct in_addr sin_addr; //32 位IP地址
char sin_zeor[8];// 不使用
}
该结构体中提到了另一个结构体 in_addr
struct in_addr{
In_addr_in s_addr; //32位 IPv4地址
}
struct sockaddr{
sa_family_t sin_family;// 地址族
char sa_data[14]; //地址信息
}
sockaddr_in 成员分析
sin_port和sin_addr分别保存16位端口号和32位ip地址
sin_zero: 没有任何特殊含义,需要使sockaddr_in和sockaddr 结构体保持一致而插入的成员
网络字节序和主机字节序
网络字节序 : 大端序格式
htons 主机字节序转化为网络字节序
网络地址的初始化与分配
点分十进制的字符串转化为32位整数 inet_addr() 函数不仅可以把IP地址转化为32位整数型,而且可以检测无效的IP地址
# include<arpa/inet.h>
in_addr_t inet_addr(const char *string);
成功返回32位大端序整数型值,失败时返回INADDR_NONE
# include<arpa/inet.h>
// inet_aton 与inet_addr 功能上完全相同,只不过运用了 in_addr结构体 ,使用频率比较高
int inet_aton(const char *string,struct in_addr *addr);
// 成功返回1(true),失败时返回0(false)
介绍一个与inet_aton函数正好相反的函数,此函数可以把网络字节序整数型IP地址转换为我们熟悉的字符串形式
#include<arpa/inet.h>
char *inet_ntoa(struct in_addr adr);
成功时返回转换的字符串地址值,失败时返回-1.
返回值类型为char类型的指针,说明字符串已经保存到内存空间中,但函数没有向程序员要求分配内存,而是在内部申请了了内存并保存了字符串。也就是说,调用完该函数后,应立即将字符串信息复制到其他内存空间。 如果再次调用inet_ntoa 函数,则有可能覆盖之前保存的字符串信息地址。
网络地址初始化
客户端地址 初始化
服务器端的准备工作通过bind函数完成,客户端则是通过connect函数完成 服务器端声明sockaddr_in结构体变量,初始化服务器端IP和套接字的端口号,然后调用bind函数。 客户端则声明sockaddr_in,初始化与之连接的服务器端IP和套接字的端口号,然后调用connect函数
INADDR_ANY
每次创建服务器端套接字都需要输入IP地址比较繁琐
INADDR_ANY 自动获取服务器端的IP地址,若服务器有多个IP地址,那么只要端口号一致,就可以从不同的IP地址接收数据。
向套接字分配网络地址
#include<sys/socket.h>
int bind(int sockfd, sturct sockaddr *myaddr, socklent_t addrlen);
// 成功返回0 ,失败返回-1
// sockfd 要分配地址信息 的套接字文件描述符
// myaddr 存有地址信息的结构体变量地址值。
//addrlen 第二个结构体变量的长度