网络通信必须解决的3大问题
udp数据发送并不能保证数据一定能到达。
1.协议(ipv4/ipv6)
2.ip
3.端口(port)
套接字:用于网络通过信的文件描述符,socket 会创建出一个通信管道,返回一个套接字。(文件描述符)
用来指向这个管道的端点,可以通过这个套接字收发数据。
int socket(int family,int type,int protocol);
功能:
创建一个用于网络通信的socket套接字(描述符)
参数:
family: 协议族(AF_INET、AF_INET6、PF_PACKET(数据链路层接口)等)
type: 套接字类(SOCK_STREAM(流式套接字)、SOCK_DGRAM(数据报套接字)、SOCK_RAW(原始套接字)
等)
protocol: 协议类别(0、IPPROTO_TCP、IPPROTO_UDP等,一般写0,自动识别
IPv4套接字地址结构
struct in_addr
{
in_addr_t s_addr;
};
{
in_addr_t s_addr;
};
struct sockaddr_in
{
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
}
{
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
}
为了使不同格式地址能被传入套接字函数,地址须
要强制转换成通用套接字地址结构
struct sockaddr
{
sa_family_t sa_family;
char sa_data[14];
};
两种地址结构使用场合
在定义源地址和目的地址结构的时候,选用struct
sockaddr_in;
例:
struct sockaddr_in my_addr;
当调用编程接口函数,且该函数需要传入地址结构
时需要用struct sockaddr进行强制转换
例:
bind(sokcfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
将本地地址协议与sockfd 绑定
my_addr.sin_family = AF_INET; //
my_addr.sin_port = htons(port);//
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);//统配地址,本机所有的ip地址都绑定到套接字指向的端点。
注意:不能绑定除本机之外的其他ip地址,如果绑定的端口,系统中有,则绑定失败。
ssize_t sendto(
int sockfd,
const void *buf,
size_t nbytes,int flags,
const struct sockaddr *to,
socklen_t addrlen
);
功能:
向to结构体指针中指定的ip,发送UDP数据,发送的地址由const sockaddr *to 结构体指定,给结构体to初始化时,定义的时候用struct sockaddr_in *(ipv4) 结构体去定义to,给到函数时,转换成通用地址结构(const struct sockaddr *)
参数:
sockfd:套接字
buf: 发送数据缓冲区
nbytes: 发送数据缓冲区的大小
flags:一般为0
to: 指向目的主机地址结构体的指针
addrlen:to所指向内容的长度
注意:
通过to和addrlen确定目的地址可以发送0长度的UDP数据包
返回值:
成功:发送数据的字符数
失败: -1
ssize_t recvfrom(
int sockfd,
void *buf,
size_t nbytes,int flags,
struct sockaddr *from,
socklen_t *addrlen
);
功能: 接收UDP数据,并将源地址信息保存在from指向的结构中
参数:
sockfd:套接字
buf: 接收数据缓冲区
nbytes:接收数据缓冲区的大小
flags: 套接字标志(常为0)
from: 源地址结构体指针,用来保存数据的来源
addrlen: from所指内容的长度
注意:
通过from和addrlen参数存放数据来源信息from和addrlen可以为NULL, 表示不保存数据来源,
定义的时候用struct sockaddr_in *(ipv4) 结构体去定义from,给到函数时,转换成通用地址结构(const struct sockaddr *)from,最后一个是from结构体的大小的地址,用变量接着,取变量的地址。
返回值:
成功:接收到的字符数
失败: -1