Linux高性能服务器编程学习笔记(一)

第5章 Linux网络编程基础API

Linux高性能服务器编程学习笔记

5.1 socket地址API

5.1.1 主机字节序和网络字节序

主机字节序–>小端 低–>低

网络字节序–>大端 高–>低

主机字节序和网路字节序转换:

/* n表示network, h表示host */
#include <netinet/in.h>
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 );

5.1.2 通用socket地址

/* 结构体sockaddr */
#include <bits/socket.h>
struct sockaddr
{
    sa_family_t sa_family;	// 地址族类型
    char sa_data[14];		// 存放地址
}

5.1.3 专用socket地址

/* 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

5.1.4 IP地址转换函数

将点分十进制字符串表示的IPv4地址转换成网络字节序表示

#include <arpa/inet.h>
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 <netinet/in.h>
#define INET_ADDRSTRLEN 16

5.2 创建socket

#include <sys/types.h>
#include <sys/socket.h>
int socket( int domain, int type, int protocol );
/* 成功返回一个socket文件描述符,失败返回-1置erroo */

domain参数指定协议族,PF_INET(IPv4)

type制定服务类型,TCP取值SOCK_STREAMUDP取值SOCK_DGRAM

protocol通常取0。

5.3 命名socket

将创建的socket与socket地址绑定,服务器需要,客户端不需要

#include <sys/types.h>
#include <sys/socket.h>
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

5.4 监听socket

服务器创建监听队列存放待处理的客户连接

#include <sys/socket.h>
int listen( int sockfd, int backlog );
/* 成功返回0,失败返回-1置errno */

backlog参数提示内核监听队列的最大长度,典型值为5,完整的连接最多有(backlog+1)个。

5.5 接受连接

从监听队列中接受一个连接

#include <sys/types.h>
#include <sys/socket.h>
int accept( int sockfd, struct sockaddr *addr, socklen_t *addrlen );
/* 成功返回新的连接socket,该socket唯一标识了被接受的这个连接,服务器可以通过读写该socket来与被接受连接对应的客户端通信。失败返回-1置errno */

addr参数用来获取被接受连接的远端socket地址,长度由addrlen指定。

5.6 发起连接

客户端主动与服务器建立连接

#include <sys/types.h>
#include <sys/socket.h>
int connect( int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen );
/* 成功返回0,失败返回-1置errno */

serv_addr参数是服务器监听的socket地址,addrlen表示这个地址的长度。

常见errno

  • ECONNREFUSED,目标端口不存在。
  • ETIMEDOUT,连接超时。

5.7 关闭连接

#include <unistd.h>
int close( int fd );

仅将引用计数-1,当fd为0时才真正关闭连接。

#include <sys/socket.h>
int shutdown( int sockfd, int howto );
/* 成功返回0,失败返回-1置errno */

howto参数可取SHUT_RDSHUT_WRSHUT_RDWR,分别表示关闭读,关闭写,关闭读写。

  • close和shutdown的区别?
  1. close仅减计数,而shutdown直接关闭
  2. shutdown可控制读写

5.8 数据读写

5.8.1 TCP数据读写

#include <sys/types.h>
#include <sys/socket.h>
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用于发送接收紧急数据。

5.9 带外标记

#include <sys/socket.h>
int sockatmark( int sockfd );

判断sockfd是否处于带外标记,即下一个被读取到的数据是否是带外数据。

是返回1,否返回0。

5.10 地址信息函数

获取本端和远端的socket地址

#include <sys/socket.h>
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获取远端。

5.11 socket选项

专门用来读取和设置socket文件描述符属性的方法

#include <sys/socket.h>
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指定要操作的哪个协议的选项。(IPv4IPv6TCP

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 发送数据超时

5.11.1 SO_REUSEADDR选项

通过设置该选项来强制使用被处于TIME_WAIT状态的连接占用的socket地址。

5.11.2 SO_RCV(SND)BUF选项

设置缓冲区大小,TCP接收缓冲区最小值256字节,发送2048字节。

有最小值是为了确保一个TCP连接拥有足够的空闲缓存来处理拥塞。

5.11.3 SO_RCV(SND)LOWAT选项

低水位标记。一般被I/O复用系统调用来判断socket是否可读或可写。

默认为1字节。

5.11.4 SO_LINGER选项

用于控制close系统调用在关闭TCP连接时的行为。需要传递linger类型的结构体。

#include <sys/socket.h>
struct linger
{
    int l_onoff;	// 开启(非0)还是关闭(0)该选项
	int l_linger;	// 滞留时间
}
发布了136 篇原创文章 · 获赞 33 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Radium_1209/article/details/105018596