网络编程
网络基本知识
| A类
| B类
| C类
| D类
子网掩码
OSI模型
TCP/IP
套接字编程
创建套接字
#include <sys/socket.h>
int socket(int domain, int type, int flag);
/* 成功返回描述符,出错返回-1 */
参数domain确定通信的特性,包括地址格式,以AF_开头,意指地址族(address family)
| domain | 描述 |
|---|---|
| AF_INET | IPv4因特网域 |
| AF_INET6 | IPv4因特网域 |
| AF_UNIX | UNIX域 |
| AF_UPSPEC | 未指定 |
参数type 确定套接字的类型
| type | 描述 |
|---|---|
| SOCK_DGRAM | 固定长度,无连接的,不可靠报文传递 |
| SOCK_RAM | IP协议的数据报接口 |
| SOCK_SEQPACKET | 固定长度,有序,可靠的,面向连接的报文传递 |
| SOCK_STREAM | 有序,可靠,双向,面向连接的字节流 |
参数protocol 通常是0,表示为给定的域和套接字类型选择默认协议
| protocol | 描述 |
|---|---|
| IPPROTO_IP | IPv4网际协议 |
| IPPROTO_IPV6 | IPv6网际协议 |
| IPPROTO_ICMP | 因特网控制报文协议 |
| IPPROTO_RAW | 原始IP数据包协议 |
| IPPROTO_TCP | 传输控制协议 |
| IPPROTO_UDP | 用户数据报协议 |
字节序
#include <arpa/inet.h>
uint32_t htonl (uint32_t hostint32); /* host to net 返回网络字节序表示的32位整数 */
uint16_t htons (uint32_t hostint16); /* host to net 返回网络字节序表示的16位整数 */
uint32_t ntohl (uint32_t netint32); /* net to host 返回主机字节序表示的32位整数 */
uint16_t ntohs (uint16_t netint16); /* net to host 返回主机字节序表示的16位整数 */
地址
linux中地址结构体定义如下
struct sockaddr {
sa_family_t sa_family; /* address family */
char sa_data[14]; /* variable-length address */
};
IPv4因特网域(AF_INET)中地址结构表示如下
#include <netinet/in.h>
struct in_addr {
in_addr_t s_addr;
};
struct scokaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
}
IPv6因特网域(AF_INET6)中地址结构表示如下
struct in6_addr {
uint8_t s6_addr[16];
};
struct sockaddr_in6 {
sa_family_t sin6_family;
in_port_t sin6_port;
uint32_t sin6_flowinfo;
struct in6_addr sin6_addr;
uint32_t sin6_scope_id; /* set of interfaces for scope */
}
它们会被强制转换成sockaddr输入到套接字的历程中
套接字与地址关联
#include <sys/socket/h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
连接
int connect (int sockfd, const struct sockaddr *addr, socklen_t len);
这里的地址是想与之通信的服务器地址
int listen(int sockfd, int backlog);
服务器调用listen来宣告他愿意接受连接请求,listen 做两件事,
- 当
socket创建套接字时,它被假设为一个主动套接字,listen函数将主动套接字换成被动套接字 - 本函数的第二个参数规定了内核应该为相应套接字排队的最大连接数
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
accept由服务器调用,用于从已完成连接的队列对头返回下一个已完成连接,如果队列为空,进程睡眠(默认)。如果accpet成功,返回值是内核自动生成的全新描述符
数据传输
ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);
ssize_t recv(int sockfd, void * buf, size_t nbytes, int flags);
/* 面向无连接 指定目标地址 */
ssize_t sendto(int socked, const void *buf, size_t n_bytes, int flags,
const struct sockaddr *destaddr, socklen_t destlen);
ssize_t recvfrom(int socked, const void *buf, size_t len, int flags,
const struct sockaddr *srcaddr, socklen_t *srclen);
| flag | 描述 |
|---|---|
| MSG_CMSG_CLOEXEC | 为UNIX域套接字上接收的文件描述符设置执行时关闭标志 |
| MSG_DONTWAIT | 启用非阻塞操作(相当于使用O_NONBLOCK) |
| MSG_ERRQUEUE | 接收错误信息作为辅助数据 |
| MSG_OOB | 如果协议支持,获取带外数据 |
| MSG_PEEK | 返回数据包内容而不真正取走数据包 |
| MSG_TRUNC | 即使数据包被截断,也返回数据包的实际长度 |
| MSG_WAITALL | 等待直到所有的数据可用(仅SOCK_STREAM) |
套接字选项
套接字机制提供了两个套接字选项接口来控制套接字的行为,可以获取或设置一下3种
- 通用选项,工作在所有的套接字类型上
- 在套接字层次管理的选项,但是依赖于下层协议的支持
- 特定于某协议的选项,每个协议独有的
#include <sys/scoket.h>
int socksetopt(int sockfd, int level, int option, const void *val, socklen_t len);
int getsockopt (int sockfd, int level, int option, void *val, socklen_t *lenp);
SOL_SOCKET 应用层
| 选项名称 | 说明 | 数据类型 |
|---|---|---|
| SO_BROADCAST | 允许发送广播数据 | int |
| SO_DEBUG | 允许调试 | int |
| SO_DONTROUTE | 不查找路由 | int |
| SO_ERROR | 获得套接字错误 | int |
| SO_KEEPALIVE | 保持连接 | int |
| SO_LINGER | 延迟关闭连接 | struct linger |
| SO_OOBINLINE | 带外数据放入正常数据流 | int |
| SO_RCVBUF | 接收缓冲区大小 | int |
| SO_SNDBUF | 发送缓冲区大小 | int |
| SO_RCVLOWAT | 接收缓冲区下限 | int |
| SO_SNDLOWAT | 发送缓冲区下限 | int |
| SO_RCVTIMEO | 接收超时 | struct timeval |
| SO_SNDTIMEO | 发送超时 | struct timeval |
| SO_REUSEADDR | 允许重用本地地址和端口 | int |
| SO_TYPE | 获得套接字类型 | int |
| SO_BSDCOMPAT | 与BSD系统兼容 | int |
IPPROTO_IP IP层/网络层
| 选项名称 | 说明 | 数据类型 |
|---|---|---|
| IP_HDRINCL | 在数据包中包含IP首部 | int |
| IP_OPTINOS | IP首部选项 | int |
| IP_TOS | 服务类型 | |
| IP_TTL | 生存时间 | int |
| IP_ADD_MEMBERSHIP | 将指定的IP加入多播组 | struct ip_mreq |
IPPRO_TCP 传输层
| 选项名称 | 说明 | 数据类型 |
|---|---|---|
| TCP_MAXSEG | TCP最大数据段的大小 | int |
| TCP_NODELAY | 不使用Nagle算法 | int |