Linux高性能服务器编程学习笔记
主机字节序–>小端 低–>低
网络字节序–>大端 高–>低
主机字节序和网路字节序转换:
/* n表示network, h表示host */
#include
unsigned long int htonl( unsigned long int hostlong );
unsigned short int htons( unsigned short int hostshort );
unsigned long int ntohl( unsigned long int netlong );
unsigned short int ntohs( unsigned short int netshort );
/* 结构体sockaddr */
#include
struct sockaddr
{
sa_family_t sa_family; // 地址族类型
char sa_data[14]; // 存放地址
}
/* Ipv4专用结构体sockaddr_in */
struct sockaddr_in
{
sa_family_t sin_family; // 地址族类型,AF_INET
u_int16_t sin_port; // 端口号,要用网络字节序表示
struct in_addr sin_addr; // IPv4地址结构体
}
struct in_addr
{
u_int32_T s_addr; // IPv4地址,网络字节序
}
注意在使用时,需要强制转换为sockaddr
。
将点分十进制字符串表示的
IPv4
地址转换成网络字节序表示
#include
int inet_pton( int af, const char* src, void* dst );
const char* inet_ntop( int af, const void* src, char* dst, socklen_t cnt );
af
指定地址族(AF_INET
),将src
转换结果存入dst
中,cnt
为指定目标存储单元大小,下面的宏可以帮助指定大小。
#include
#define INET_ADDRSTRLEN 16
#include
#include
int socket( int domain, int type, int protocol );
/* 成功返回一个socket文件描述符,失败返回-1置erroo */
domain
参数指定协议族,PF_INET(IPv4)
。
type
制定服务类型,TCP
取值SOCK_STREAM
,UDP
取值SOCK_DGRAM
。
protocol
通常取0。
将创建的socket与socket地址绑定,服务器需要,客户端不需要
#include
#include
int bind( int sockfd, const struct sockaddr* my_addr, socklen_t addrlen );
/* 成功返回0,失败返回-1置errno */
将my_addr
所指的socket
地址分配给未命名的sockfd
文件描述符,addrlen
参数指出socket
地址的长度。
常见errno
:
EACCES
,受保护地址,如知名服务端口EADDRINUSE
,地址正在使用,如TIME_WAIT
服务器创建监听队列存放待处理的客户连接
#include
int listen( int sockfd, int backlog );
/* 成功返回0,失败返回-1置errno */
backlog
参数提示内核监听队列的最大长度,典型值为5,完整的连接最多有(backlog+1)个。
从监听队列中接受一个连接
#include
#include
int accept( int sockfd, struct sockaddr *addr, socklen_t *addrlen );
/* 成功返回新的连接socket,该socket唯一标识了被接受的这个连接,服务器可以通过读写该socket来与被接受连接对应的客户端通信。失败返回-1置errno */
addr
参数用来获取被接受连接的远端socket
地址,长度由addrlen
指定。
客户端主动与服务器建立连接
#include
#include
int connect( int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen );
/* 成功返回0,失败返回-1置errno */
serv_addr
参数是服务器监听的socket
地址,addrlen
表示这个地址的长度。
常见errno
:
ECONNREFUSED
,目标端口不存在。ETIMEDOUT
,连接超时。#include
int close( int fd );
仅将引用计数-1,当fd
为0时才真正关闭连接。
#include
int shutdown( int sockfd, int howto );
/* 成功返回0,失败返回-1置errno */
howto
参数可取SHUT_RD
、SHUT_WR
、SHUT_RDWR
,分别表示关闭读,关闭写,关闭读写。
#include
#include
ssize_t recv( int sockfd, void *buf, size_t len, int flags );
ssize_t send( int sockfd, const void *buf, size_t len, int flags );
/* 成功返回实际读写长度,失败返回-1置errno */
buf
数据,len
长度,flags
一般为0,MSG_OOB
用于发送接收紧急数据。
#include
int sockatmark( int sockfd );
判断sockfd
是否处于带外标记,即下一个被读取到的数据是否是带外数据。
是返回1,否返回0。
获取本端和远端的socket地址
#include
int getsockname( int sockfd, struct sockaddr* address, socklen_t* address_len );
int getpeername( int sockfd, struct sockaddr* address, socklen_t* address_len );
/* 成功返回0,失败返回-1置errno */
getsockname
获取本端,getpeername
获取远端。
专门用来读取和设置socket文件描述符属性的方法
#include
int getsockopt( int sockfd, int level, int option_name, void* option_value,
socklen_t* restrict option_len );
int getsockopt( int sockfd, int level, int option_name, const void* option_value,
socklen_t* restrict option_len );
level
指定要操作的哪个协议的选项。(IPv4
、IPv6
、TCP
)
option_name
指定选项的名字。
option_value
被操作选项的值。
option_len
被操作选项的长度。
重要的socket选项:
level | option_name | 数据类型 | 说明 |
---|---|---|---|
SOL_SOCKET | SO_REUSEADDR | int | 重用本地地址 |
SO_RCVBUF | int | TCP接收缓冲区大小 | |
SO_SNDBUF | int | TCP发送缓冲区大小 | |
SO_LINGER | linger | 若有数据待发送,则延迟关闭 | |
SO_RCVLOWAT | int | TCP接收缓存区低水位标记 | |
SO_SNDLOWAT | int | TCP发送缓存区低水位标记 | |
SO_RCVTIMEO | timeval | 接受数据超时 | |
SO_SNDTIMEO | timeval | 发送数据超时 |
通过设置该选项来强制使用被处于TIME_WAIT
状态的连接占用的socket
地址。
设置缓冲区大小,TCP接收缓冲区最小值256字节,发送2048字节。
有最小值是为了确保一个TCP连接拥有足够的空闲缓存来处理拥塞。
低水位标记。一般被I/O复用系统调用来判断socket是否可读或可写。
默认为1字节。
用于控制close
系统调用在关闭TCP
连接时的行为。需要传递linger
类型的结构体。
#include
struct linger
{
int l_onoff; // 开启(非0)还是关闭(0)该选项
int l_linger; // 滞留时间
}