一、套接字
基本特点:socket是一种接口技术,被抽象成一个文件操作,可以让进程之间通信,也可以让不同计算机的进程通信(网络)。
int socket(int domain, int type, int protocol);
功能:创建套接字
domain:
AF_UNIX/AF_LOCAL 本地通信,进程间通信
AF_INET 基于IPv4地址通信
AF_INET6 基于IPv6地址通信
type:
SOCK_STREAM 数据流协议
SOCK_DGRAM 数据报协议
protocol:特殊通信协议,一般不用,写0即可。
返回值:成功返回套接字描述符,失败返回-1。
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:绑定socket和地址(文件路径或网络地址)
sockfd:socket描述符
addr:地址结构体
// 基本地址类型
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
// 本地地址类型 #include <sys/un.h>
struct sockaddr_un{
sa_family_t sun_family; // 地址簇
char sun_path[108]; // socket文件路径
};
// 网络地址类型 #include <netinet/in.h>
struct sockaddr_in{
sa_family_t sin_family; // 地址簇
in_port_t sin_port; // 端口号
struct in_addr sin_addr;// IP地址
};
struct in_addr{
in_addr_t s_addr;
}
addrlen:地址结构体的字节数
返回值:成功返回0,失败返回-1。
int listen(int sockfd, int backlog);
功能:监听socket,数据流通信时使用
sockfd:socket描述符
backlog:排队数量
返回值:成功返回0,失败返回-1。
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:连接socket
sockfd:socket描述符
addr:目标地址
addrlen:地址的字节数
返回值:成功返回0,失败返回-1。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:等待连接
sockfd:socket描述符
addr:获取连接者的地址
addrlen:既输入双输出
既告诉accept函数当前系统地址结构体的字节数,同时也获取发者地址结构体的字节数
返回值:返回一个建议连接后的socket描述符
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:从socket读取数据,数据流通信时使用
sockfd:建立连接后的socket描述符
buf:存储数据的缓冲区地址
len:缓冲区的字节数
flags: 一般写0即可
MSG_OOB 优先接收外带数据
MSG_DONTWAIT 不阻塞
返回值:接收到的字节数,-1出现错误,0连接断开。
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:向socket发送数据,数据流通信时使用
sockfd:建立连接后的socket描述符
buf:待发送的数据首地址
len:要发送的字节数
flags:一般写0即可
MSG_OOB 优先紧急数据
MSG_DONTWAIT 不阻塞
返回值:成功发送的字节数,出错返回-1。
int close(int fd);
功能:关闭socket
TCP网络通信编程模型:
计算机S 计算机C
创建套接字 创建套接字
准备通信地址(自己的) 准备通信地址(计算机S,与C在同一局域网或S是公用IP)
绑定套接字和地址 连接计算S
监听 …
等待连接 …
接收/发送数据 发送/接收数据
关闭套接字 关闭套接字
多路复用:
由于为了实现服务器的并发(同时服务多个客户端),需要为每个客户端创建一个进程来为它服务,但创建进程、销毁进程非常浪费时间与资源,这个问题有两种解决方案:
1、多路复用:一个进程监控所有的客户端fd+服务端fd。
2、多线程:为每个客户端创建一个线程进行服务。
由于有些读写函数需要以阻塞状态调用,同时可能有多个文件描述需要同时读写,多路复用就是同时监控多个文件的描述符。
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能:监控若干个文件描述符
nfds:最大的文件描述符加1
readfds:需要监控读操作的文件描述符集合,既输入又是输出。
writefds:需要监控写操作的文件描述符集合,既输入又是输出。
exceptfds:需要监控异常的文件描述符时间,既输入又是输出。
timeout:倒计时时间
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
void FD_CLR(int fd, fd_set *set);
功能:从集合中删除fd
int FD_ISSET(int fd, fd_set *set);
功能:测试集合是否有fd存在
void FD_SET(int fd, fd_set *set);
功能:向集合中添加文件描述符
void FD_ZERO(fd_set *set);
功能:清空文件描述符
int epoll_create(int size);
功能:创建epoll对象
size:epoll对象的大小,因为内核会自动调整epoll对象的大小,因此该参数目前已经作废。
返回值:epoll对象的描述符
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:操作epoll对象,可以添加、删除文件描述符
epfd:epoll对象描述符
op:
EPOLL_CTL_ADD 添加文件描述符
EPOLL_CTL_MOD 修改文件描述符的监控事件
EPOLL_CTL_DEL 删除文件描述符
fd:
要操作的文件描述符
event:
struct epoll_event {
uint32_t events; /* Epoll events */
EPOLLIN 读事件
EPOLLOUT 写事件
epoll_data_t data; /* User data variable */
};
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
功能:监控epoll对象中的文件描述符
epfd:epoll对象
events:保存发生事件的文件描述符集合
maxevents:最多保存多少个文件描述符
timeout:等待时间,1000/1秒,-1则一直等待。
返回值:事件发生手文件描述符个数
常考面试题:select与epoll的区别。
本地字节序与网络字节序转换:
uint32_t htonl(uint32_t hostlong);
功能:把4字节的本地字节序数据转换成网络字节序
uint16_t htons(uint16_t hostshort);
功能:把2字节的本地字节序数据转换成网络字节序
uint32_t ntohl(uint32_t netlong);
功能:把4字节网络字节序数据转换成本地字节序
uint16_t ntohs(uint16_t netshort);
功能:把2字节网络字节序数据转换成本地字节序
IPv4地址转换:
int inet_aton(const char *cp, struct in_addr *inp);
功能:把点十进制的IP地址转换成 struct sockaddr_in中的sin_addr成员类型。
in_addr_t inet_addr(const char *cp);
功能:把点十进制的IP地址转换成 struct sockaddr_in中的sin_addr.s_addr,通过返回值返回。
in_addr_t inet_network(const char *cp);
功能:把点十进制的IP地址转换成,转换成本地字节序的二进制。
char *inet_ntoa(struct in_addr in);
功能:struct sockaddr_in中的sin_addr成员转换成点分十进制的ip地址。
struct in_addr inet_makeaddr(int net, int host);
功能:把网络地址与主机地址合并成IP地址
in_addr_t inet_lnaof(struct in_addr in);
功能:计算IP地址的主机地址
ip & ~掩码
in_addr_t inet_netof(struct in_addr in);
功能:计算IP地址的网络地址
ip & 掩码
UDP网络通信:
UDP是无连接的通信协议,准备好地址之后可以直接发送或接收数据。
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
功能:发送数据
sockfd:发送者的socket描述符
buf:待发送的数据
len:数据的长度
flags:一般写0即可。
dest_addr:目标地址
addrlen:地址的长度
返回值:成功发送的数据的字节数
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
功能:接收数据
sockfd:接收者的socket描述符
buf:存储数据的缓冲区
len:缓冲区的长度
flags:一般写0即可
src_addr:存储发送者的地址
addrlen:既是输入(当前系统地址的字节数)也是输出(获取发送者地址的字节数),存储发送者地址的长度。
返回值:成功接收到的数据的字节数。
UDP网络通信编程模型:
计算机S 计算机C
创建socket对象 创建socket对象
准备通信地址 准备通信地址(S的地址)
绑定socket对象和地址
接收/返回数据 发送/接收数据
关闭socket对象 关闭socket对象
UDP广播通信:
广播就是发送者发出一条数据,路由器把这条数据向局域网中的所有计算转发一次。
如何广播:就是向一个特殊地址发送数据,同时还要设置sock对象的属性。
广播地址就是除了网络地址其它位全为1。
192.168.0.113
255.255.255.0
192.168.0 网络地址
113 主机地址
192.168.0.255 广播地址
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
功能:设置socket对象的属性
sockfd:socket对象的描述符
level:要设置的协议层
SOL_SOCKET
SO_BROADCAST 广播
IPPROTO_IP
IP_MULTICAST_TTL 多播
IPPROTO_TCP
optname:要设置的选项名
optval:存储要修改的值的缓冲区
optlen:缓冲区的长度
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);