沈阳网站建设方案,襄阳做网站价格,WordPress安全社区,深圳市宝安区投资推广署官网创建套接字函数 socket 【头文件】 #include sys/types.h #include sys/socket.h 【函数原型】 int socket(int domain, int type, int protocol); 【函数功能】 socket 函数创建一个通信端点#xff0c;并返回一个引用该端点的文件描述符#xff0c;…创建套接字函数 socket 【头文件】 #include sys/types.h #include sys/socket.h 【函数原型】 int socket(int domain, int type, int protocol); 【函数功能】 socket 函数创建一个通信端点并返回一个引用该端点的文件描述符称为套接字。 【参数含义】 [domain]: 地址族Address Family也就是 IP 地址类型 [type]:创建的套接字类型主要有 SOCK_STREAM(流式套接字),SOCK_DGRAM(数据包套接字)等 [protocol]:指定具体的传输协议类型。通常某协议中只有一种特定类型这样 protocol参数仅能设置为 0但是有些协议有多种特定的类型就需要设置这个参数来选择特定的类型。 【返回值】 成功返回一个套接字描述符(0,与文件描述符类型) 失败返回-1.errno 被设置 【备注】 domain 参数可选字段 以下是 socket.h 文件中的宏可以看到 AF_和 PF_都是可以的所以在之后的代码中如果看到 上面表格中不存在的字段时不要认为写错了哟。 #define AF_UNSPEC PF_UNSPEC
#define AF_LOCAL PF_LOCAL
#define AF_UNIX PF_UNIX
#define AF_FILE PF_FILE
#define AF_INET PF_INET
#define AF_AX25 PF_AX25
#define AF_IPX PF_IPX
#define AF_APPLETALK PF_APPLETALK
#define AF_NETROM PF_NETROM
#define AF_BRIDGE PF_BRIDGE
#define AF_ATMPVC PF_ATMPVC
#define AF_X25 PF_X25
#define AF_INET6 PF_INET6
#define AF_ROSE PF_ROSE
#define AF_DECnet PF_DECnet
#define AF_NETBEUI PF_NETBEUI
#define AF_SECURITY PF_SECURITY
#define AF_KEY PF_KEY
#define AF_NETLINK PF_NETLINK
#define AF_ROUTE PF_ROUTE
#define AF_PACKET PF_PACKET
#define AF_ASH PF_ASH
#define AF_ECONET PF_ECONET
#define AF_ATMSVC PF_ATMSVC
#define AF_RDS PF_RDS
#define AF_SNA PF_SNA
#define AF_IRDA PF_IRDA
#define AF_PPPOX PF_PPPOX
#define AF_WANPIPE PF_WANPIPE
#define AF_LLC PF_LLC
#define AF_IB PF_IB
#define AF_MPLS PF_MPLS
#define AF_CAN PF_CAN
#define AF_TIPC PF_TIPC
#define AF_BLUETOOTH PF_BLUETOOTH
#define AF_IUCV PF_IUCV
#define AF_RXRPC PF_RXRPC
#define AF_ISDN PF_ISDN
#define AF_PHONET PF_PHONET
#define AF_IEEE802154 PF_IEEE802154
#define AF_CAIF PF_CAIF
#define AF_ALG PF_ALG
#define AF_NFC PF_NFC
#define AF_VSOCK PF_VSOCK
#define AF_KCM PF_KCM
#define AF_QIPCRTR PF_QIPCRTR
#define AF_SMC PF_SMC
#define AF_MAX PF_MAX
type 可选字段 error 字段: 【示例程序】 创建一个用于 TCP 通信的套接字 int sockfd socket ( AF_INET , SOCK_STREAM , 0 ); 创建一个用于 UDP 通信的套接字 int sockfd socket ( AF_INET , SOCK_DGRAM , 0 ); 创建一个用于本地通信的套接字 int sockfd socket ( PF_UNIX , SOCK_STREAM , 0 ); 网络地址结构体 sockaddr 因为套接字接口既可以用于以太网,也可以用于其他类型的通信,如蓝牙等等不同的通信协 议,它们的地址结构是不一样的,所以设计了一个通用地址结构体: 类型为 struct sockaddr /* 描述通用套接字地址的结构 */
struct sockaddr
{__SOCKADDR_COMMON (sa_); /* 常用数据:地址族和长度. */char sa_data[14]; /* 地址数据. */
}; socket 中所有的函数都是使用上面的结构来表示一个地址(可以任意协议族的地址)
IPV4 的地址信息结构体为
struct sockaddr_in {__kernel_sa_family_t sin_family; /*指定的协议族,AF_INTE*/__be16 sin_port; /* 端口号(网络字节序)*/struct in_addr sin_addr; /*IP 地址*//*填充到结构 sockaddr 的大小,保证所有协议的地址结构体都可以使用 socket 表示. */unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -sizeof(unsigned short int) - sizeof(struct in_addr)];
};
其中
struct in_addr {__be32 s_addr; //IP 地址,in_addr_t 类型32 位无符号整型
};
使用上面结构体需要的头文件为 #include arpa/inet.h #include netinet/in.h // 为了使用 IPV4 地址结构体 本地通信的地址信息结构体为
struct sockaddr_un {__kernel_sa_family_t sun_family; /* 协议族AF_UNIX */char sun_path[UNIX_PATH_MAX]; /* 路径名因为本地通信就是进程间通信没有 IP 地址一言所以需要一个计算机中的目录路径就像 ftok 通过路径名获取 key 一样 */
};
使用上面结构体需要的头文件为 #include arpa/inet.h #include netinet/un.h // 为了使用 IPV4 地址结构体 点分式 IP 地址转 in_addr
点分式 ip 转换成 in_addr 类型(inet_aton) 【头文件】 #include sys/socket.h
#include netinet/in.h
#include arpa/inet.h 【函数原型】 int inet_aton(const char *cp, struct in_addr *inp); 【函数功能】 将点分式 ip 地址转换成 in_addr 类型 【参数含义】 [cp]: IP 地址的点分式字符串 [inp]:保存转换好的 in_addr 结构体类型 【返回值】 成功返回 0, 失败返回-1,同时 errno 被设置 【示例】 struct sockaddr_in saddr ; inet_aton ( 192.168.41.243 , saddr . sin_addr ); 点分式 ip 转换 in_addr_t 类型(inet_addr) 【头文件】 #include sys/socket.h
#include netinet/in.h
#include arpa/inet.h 【函数原型】 in_addr_t inet_addr(const char *cp); 【函数功能】 将点分式 ip 地址转换成 in_addr_t 类型 , 转换后是网络字节序 【参数含义】 [cp]: IP 地址的点分式字符串 【返回值】 成功返回转换好的 in_addr_t 类型的 ip 地址 失败返回-1 【备注】 当 IP 为 255.255.255.255 时函数会认为这是个无效 IP,这属于 linux 的遗留问题 【示例】 struct sockaddr_in Saddr; //保存服务器的地址信息的结构体
memset(Saddr,0,sizeof(struct sockaddr_in)); //清空结构体
Saddr.sin_family AF_INET; //协议族,AF_INET 表示使用 IPV4 的协议族
Saddr.sin_port htons(atoi(argv[2])); //端口号,但是要求的是网络字节序
Saddr.sin_addr.s_addr inet_addr(argv[1]); //32bit 的一个 IP 地址 点分式 ip 转换 in_addr_t 类型(inet_network) 【头文件】 #include sys/socket.h
#include netinet/in.h
#include arpa/inet.h 【函数原型】 in_addr_t inet_network(const char *cp); 【函数功能】 将点分式 ip 地址转换成 in_addr_t 类型转换后是主机字节序 【参数含义】 [cp]: IP 地址的点分式字符串 【返回值】 成功返回转换好的 in_addr_t 类型的 ip 地址 失败返回-1 【备注】 当 IP 为 255.255.255.255 时函数会认为这是个无效 IP,这属于 linux 的遗留问题 适用与 IPV6 协议的 ip 转换(inet_pton) 【头文件】 #include arpa/inet.h 【函数原型】 int inet_pton(int af, const char *src, void *dst); 【函数功能】 将字符串类型的 IP 地址转换为二进制类型。 【参数含义】 [af]: 表示网络类型的协议族如在 IPv4 下的值为 AF_INET; [src]: 存放要转换的字符串 [dst]:存放转换后的结果在 IPv4 下dst 指向结构 struct in_addr 的指针。 【返回值】 当函数 inet_pton()的返回值为-1 的时候通常是用于 af 所指定的协议族不支持造成此时 errno 的返回值为 EAFNOSUPPORT;当函数的返回值为 0 时表示 src 指向的值不是合法的 IP地址当函数的返回值为正值时表示转换成功。 网络 IP 转点分式
in_addr 结构体类型 ip 转点分式(inet_ntoa) 【头文件】 #include sys/socket.h
#include netinet/in.h
#include arpa/inet.h 【函数原型】 char * inet_ntoa ( struct in_addr in); 【函数功能】 将 in_addr 类型 ip 转换成点分式表示 【参数含义】 [in]: 要转换的 in_addr 类型 IP 【返回值】 成功返回转换好的点分式 ip 地址 失败返回 NULL 【示例】 打印客户端的 IP 地址 printf ( [ %s ] \n , inet_ntoa ( addr . sin_addr )); 适用与 IPV6 协议的 ip 转换(inet_pton) 【头文件】 #include arpa/inet.h 【函数原型】 const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); 【函数功能】 将二进制的网络 IP 地址转换为字符串。 【参数含义】 [af]: 表示网络类型的协议族如在 IPv4 下的值为 AF_INET; [src]:为需要转换的二进制 ip 地址在 IPv4 下dst 指向结构 struct in_addr 的指针。 [dst]:存放转换后的结果 [size]:为 dst 的空间大小 【返回值】 返回一个指向 dst 的指针。当发生错误时返回 NULL。当 af 设定的协议族不支持时errno 设置为 EAFNOSUPPORT;当 dst 缓冲区大小过小的时候 errno 的值为 ENOSPC inet_makeaddr()函数,inet_lnaof()函数和 inet_netof()函数
inet_makeaddr 函数 【头文件】 #include sys/socket.h
#include netinet/in.h
#include arpa/inet.h 【函数原型】 struct in_addr inet_makeaddr(int net,int host) 【函数功能】 一个主机的 IP 地址分为网络地址和主机地址inet_makeaddr()函数将主机字节序的网络地址 net 和主机地址 host 合并成一个网络字节序的 IP 地址。 【参数含义】 [net]: 存放网络号参数二进制形式的网络字节序 [host]: 存放主机号地址二进制形式的主机字节序 【返回值】 返回一个网络字节序的 IP 地址 【示例】 unsigned long net,host;
net 0x0000007F;
host 0x00000001;
struct in_addr ip inet_makeaddr(net,host); 主机地址提取函数 inet_lnaof 【头文件】 #include sys/socket.h
#include netinet/in.h
#include arpa/inet.h 【函数原型】 in_addr_t inet_lnaof(struct in_addr in) 【函数功能】 从参数 in 中提取出主机地址,执行成功后返回主机字节顺序形式的主机地址。 例如172.17.242.131 属于 B 类地址则主机号为低 16 位主机地址为 0.0.242.131按主机字节顺序输出则为 0xf283。 【参数含义】 [in]: 存放的是主机字节序的二进制形式的 IP 地址 【返回值】 返回主机字节序的二进制形式的 IP 主机部分的数值 【示例】 const char * addr 127.0.0.1 ; unsigned long ip inet_network ( addr ); unsigned long host_id inet_lnaof ( ip ); 网络地址提取函数 inet_netof 【头文件】 #include sys/socket.h
#include netinet/in.h
#include arpa/inet.h 【函数原型】 in_addr_t inet_netof(struct in_addr in) 【函数功能】 该函数从参数 in 中提取出网络地址执行成功后返回主机字节顺序形式的网络地址。 如172.17.242.131 属于 B 类地址则高 16 位表示网络号网络地址为 172.17.0.0。 【参数含义】 [in]: 存放的是主机字节序的二进制形式的 IP 地址 【返回值】 返回主机字节序的二进制形式的 IP 网络部分的数值 【示例】 const char * addr 127.0.0.1 ; unsigned long ip inet_network ( addr ); unsigned long network_id inet_netof ( ip ); 主机字节序和网络字节序之间的转换 API
在 linux 中提供了下面四个函数用于网络字节序和主机字节序之间的转换。 主机转网络 htonl, htons 网络转主机 ntohl, ntohs 其中函数名字的含义如下 h: host 主机字节序(就是我们所说到的端口号) n: network 网络字节序 l: long ---32 位 s: short ---16 位 32 位主机字节序转网络字节序(htonl) 【头文件】 #include arpa/inet.h 【函数原型】 uint32_t htonl(uint32_t hostlong); 【函数功能】 将 32 位的主机字节序 hostlong 转换为网络字节序返回 【参数含义】 [hostlong]: 待转换的 32 位主机字节序 【返回值】 返回转换后的网络字节序 16 位主机字节序转网络字节序(htons) 【头文件】 #include arpa/inet.h 【函数原型】 uint16_t htons(uint16_t hostlong); 【函数功能】 将 16 位的主机字节序 hostlong 转换为网络字节序返回 【参数含义】 [hostlong]: 待转换的 16 位主机字节序 【返回值】 返回转换后的网络字节序 【示例】 端口号的转换 address . sin_port htons ( atoi (port)); // 将端口号 port 转换为网络字节序 32 位网络字节序转主机字节序(ntohl) 【头文件】 #include arpa/inet.h 【函数原型】 uint32_t ntohl(uint32_t netlong); 【函数功能】 将 32 位的网络字节序 netlong 转换为主机字节序返回 【参数含义】 [netlong]: 待转换的 32 位网络字节序 【返回值】 返回转换后的主机字节序 16 位网络字节序转主机字节序(ntohs) 【头文件】 #include arpa/inet.h 【函数原型】 uint16_t ntohs(uint16_t netlong); 【函数功能】 将 16 位的网络字节序 netlong 转换为主机字节序返回 【参数含义】 [netlong]: 待转换的 16 位网络字节序 【返回值】 返回转换后的主机字节序 【示例】 打印连接的客户端的 IP 和端口号 printf ( 客户端 IP: %s , 客户端 Port: %d \n , inet_ntoa ( caddr . sin_addr ), ntohs ( caddr . sin_port )); 服务器绑定(bind) 【头文件】 #include sys/types.h
#include sys/socket.h 【函数原型】 int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); 【函数功能】 bind 就是将一个本地协议地址赋予一个套接字对于网络协议协议地址就是 32 位的 IPV4 地址或 128 位的 IPV6 地址与 16 位的 TCP 或 UDP 端口号的组合。 【参数含义】 [sockfd]: 待赋予的套接字 [addr]:保存了网络协议地址的结构体指针IPV4 为 sockaddr_in。 [addrlen]:协议地址结构体的大小 【返回值】 成功返回 0, 失败返回-1,同时 errno 被设置 【示例】 //2.绑定一个通信 IP 地址(作为服务器本身的 IP)
struct sockaddr_in saddr; //保存服务器的地址(IPport)
memset(saddr,0,sizeof(struct sockaddr_in)); //清空结构体
saddr.sin_family AF_INET;
inet_aton(argv[1], saddr.sin_addr);
saddr.sin_port htons(atoi(argv[2]));
int ret bind(sockfd,(struct sockaddr *)saddr,sizeof(saddr));
if(ret -1)
{perror(bind error);exit(-1);
} 服务器监听函数(listen) 【头文件】 #include sys/types.h
#include sys/socket.h 【函数原型】 int listen(int sockfd, int backlog); 【函数功能】 通过 socket 函数创建的套接字时它是被假设成一个主动套接字的也就是说它是一个调用 connect 去连接服务器的客户端套接字而 listen 函数就是将一个未连接的套接字变成一个被动套接字指使内核应该接收指向该套接字的连接请求根据 TCP 三次握手的示例图得知调用 listen 函数会导致套接字从 CLOSED 状态变为 LISTEN 状态同时 listen 函数的第二个参数还将指定与该套接字连接的最大个数。 【参数含义】 [sockfd]: 待监听的套接字 [backlog]: 监听队列上面最大的请求数量 【返回值】 成功返回 0, 失败返回-1,同时 errno 被设置 【示例】 //3.开启对一个套接字的监听 listen ( sockfd , 250 ); 等待客户连接函数(accept) 【头文件】 #include sys/types.h
#include sys/socket.h 【函数原型】 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 【函数功能】 accept 函数用于从已完成连接队列队头返回下一个已完成的连接如果队列为空则程序睡眠(假定套接字为默认的阻塞模式) 【参数含义】 [sockfd]: 服务器套接字 [addr]:用来保存待连接的客户端协议地址结构体 [addrlen]:用来保存待连接的 客户端协议地址结构体大小 【返回值】 成功返回一个连接套接字表示与一个特定的客户端的连接,后序与这个客户端的通信,都是通过这个连接套接字 失败返回-1同时 error 被设置 【示例】 struct sockaddr_in caddr ; // 保存客户端的地址 (IPport) socklen_t len sizeof ( caddr ); int confd accept (sockfd,( struct sockaddr * ) caddr , len ); 请求服务器连接函数(connect) 【头文件】 #include sys/types.h
#include sys/socket.h 【函数原型】 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 【函数功能】 connect 函数用于客户端和服务器建立连接 【参数含义】 [sockfd]: 客户端套接字 [addr]:保存待连接的服务器协议地址结构体 [addrlen]:保存待连接的 服务器协议地址结构体大小 【返回值】 成功返回 0 失败返回-1,同时 errno 被设置 【示例】 struct sockaddr_in Saddr; //保存服务器的地址信息的结构体
memset(Saddr,0,sizeof(struct sockaddr_in)); //清空结构体
Saddr.sin_family AF_INET; //协议族,AF_INET 表示使用 IPV4 的协议族
Saddr.sin_port htons(atoi(3456));//端口号,但是要求的是网络字节序
Saddr.sin_addr.s_addr inet_addr(192.168.41.234);
int r connect(sock,(struct sockaddr *)Saddr,sizeof(Saddr));
if(r -1) //连接失败
{perror(connect error);return -1;
} 网络消息发送 API 使用 write 发送 write 函数操作套接字发送消息类似于操作文件描述符向文件中写入数据write 的函数原型如下 ssize_t write ( int fd, const void * buf, size_t count); 在使用 write 进行套接字网络通信时通常将套接字写入第一个参数发送的内容写入第二个参数第三个参数是发送的大小发送的大小是由窗口大小决定的一般每次最多发送1024 字节就行了。 使用示例 char buf[1024] {0};
memset(buf,0,sizeof(buf));
scanf(%[^\n],buf);
printf(%ld\n,strlen(buf));
int ret write(sock,buf,strlen(buf));
if(ret 0)
{perror(sendto error);return -1;
} 使用 writev 发送 【头文件】 #include sys/uio.h 【函数原型】 ssize_t writev(int fd, const struct iovec *iov, int iovcnt); 【函数功能】 和 write 函数类似不过该函数的第二个参数是一个 struct iovec 的数组该结构体中有两个元素一个表示一个地址一个表示地址偏移量第三个参数表示 struct iovec 数组的元素个数。 【参数含义】 [fd]: 描述符(文件描述符或套接字描述符) [iov]:struct iovec 结构体数组存放待发送的消息 struct iovec { void * iov_base ; // 内容的地址 __kernel_size_t iov_len ; // 偏移量 }; [iovcnt]: struct iovec 结构体数组 的元素个数 【返回值】 成功返回发送的字节数 失败返回-1,同时 errno 被设置 【示例】 struct iovec iv [ 2 ]; iv [ 0 ].iov_base header_buf; iv [ 0 ].iov_len strlen ( header_buf ); iv [ 1 ].iov_base file_buf; iv [ 1 ].iov_len file_stat.st_size; ret writev (confd, iv , 2 ); 使用 send 发送 【头文件】 #include sys/types.h
#include sys/socket.h 【函数原型】 ssize_t send(int sockfd, const void *buf, size_t len, int flags); 【函数功能】 在套接字通信中和 write 函数类似不过多了第四个参数是一个发送标志一般为 0 【参数含义】 [sockfd]: 通信套接字 [buf]:待发送的内容 [len]: 发送内容的字节大小 [flags]: 发送标志一般为 0也可以是几个宏的组合值 【返回值】 成功返回发送的字节数 失败返回-1,同时 errno 被设置 【示例】 ret send ( sockfd , nishiliangzaiya , 15 , 0 ); 【flags 标志选项】 MSG_CONFIRM 告诉链路层发生了向前的进展:你从另一方获得了成功的回复。如果链路层没 有这样做它将定期重新探测邻居(例如通过单播 ARP)。仅在 SOCK_DGRAM 和 SOCK_RAW 套接 字上有效目前仅对 IPv4 和 IPv6 实现。 MSG_DONTROUTE不要使用网关来发送数据只发送到直接连接的主机上。通常只有诊断或者路由程序会使用这只针对路由的协议族定义的数据包的套接字没有。 MSG_DONTWAIT 启用非阻塞操作如果操作阻塞就返回 EAGAIN 或 EWOULDBLOCK MSG_EOR 当支持 SOCK_SEQPACKET 时终止记录。 MSG_MORE 调用方有更多的数据要发送。这个标志与 TCP 或者 udp 套接字一起使用 MSG_NOSIGNAL 当另一端中断连接时请求不向流定向套接字上的错误发送 SIGPIPE EPIPE 错误仍然返回。 MSG_OOB在支持此概念的套接字上发送带外数据例如SOCK_STREAM 类型底层协议还必须支持带外数据 使用 sendto 发送 【头文件】 #include sys/types.h
#include sys/socket.h 【函数原型】 ssize_t sendto(int sockfd, const void *buf, size_t len,int flags,const struct sockaddr *dest_addr, socklen_t addrlen); 【函数功能】 在套接字通信中和 send 函数类似不过多了两个参数用来指定接收者的协议地址和协议地 址大小因为 UDP 是没有结果连接的所以一般使用该函数进行通信 【参数含义】 [sockfd]: 通信套接字 [buf]:待发送的内容 [len]: 发送内容的字节大小 [flags]: 发送标志一般为 0也可以是几个宏的组合值 [dest_addr]:接收者的协议地址 [addrlen]:接收者协议地址的大小 【返回值】 成功返回发送的字节数 失败返回-1,同时 errno 被设置 【示例】 TCP 通信使用示例直接将后面两个参数置空处理 ret sendto (sockfd, nishiliangzaima , 15 , 0 , NULL , 0 ); if (ret - 1 ) { perror ( sendto error ); } UDP 通信使用示例 char buf [ 1024 ] { 0 }; fgets ( buf , 1024 , stdin ); int ret sendto ( sockfd , buf , strlen ( buf ), 0 ,( struct sockaddr * ) addr , sizeof ( addr )); 使用 sendmsg 发送 【头文件】 #include sys/types.h
#include sys/socket.h 【函数原型】 ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 【函数功能】 在套接字通信中和 sendto 函数类似不过 sendmsg 函数将发送的内容和接收者的协议地址 都放入了一个 struct msghdr 的结构体中。 【参数含义】 [sockfd]: 通信套接字 [msg]:保存了发送内容和协议地址等信息的结构体指针 struct msghdr
{void *msg_name; /* 发送/接收方的协议地址 */socklen_t msg_namelen; /* 地址数据长度 */struct iovec *msg_iov; /* 要发送/接收的数据向量*/size_t msg_iovlen; /*向量中的元素数。*/void *msg_control; /*辅助数据(例如 BSD 文件传递)*/size_t msg_controllen; /*辅助数据缓冲区长度。*/int msg_flags; /* 接收到的消息上的标志。忽略 */
}; [flags]: 发送标志一般为 0也可以是几个宏的组合值 【返回值】 成功返回发送的字节数 失败返回-1,同时 errno 被设置 读取网络消息 API 使用 read 读取 read 函数操作套接字发送消息类似于操作文件描述符向文件中读取数据read 的函数原型 如下 ssize_t read ( int fd, void * buf, size_t count); 在使用 read 进行套接字网络通信时通常将套接字写入第一个参数保存读取的内容的数组写入第二个参数第三个参数是每次读取的大小。 使用示例 char buf [ 1024 ]; memset ( buf , 0 , sizeof ( buf )); int ret read ( client , buf , sizeof ( buf )); 使用该方式的注意事项 使用 read 进行套接字通信时如果网络两端通信的流量很大的话就会出现数据丢失的现象例如服务器向客户端传输大文件时如果使用 read 去进行读取的话可能会使得读取得文件丢失。这个现象的原因在于内核中用于套接字的缓冲区可能已达到了极限。此时所需要的是调用者再次调用 read 函数以输出剩余的字节。 使用 readv 读取 【头文件】 #include sys/uio.h 【函数原型】 ssize_t readv(int fd, const struct iovec *iov, int iovcnt); 【函数功能】 和 read 函数类似不过该函数的第二个参数是一个 struct iovec 的数组该结构体中有两个元素一个表示一个地址一个表示地址偏移量第三个参数表示 struct iovec 数组的元素个数。 【参数含义】 [fd]: 描述符(文件描述符或套接字描述符) [iov]:struct iovec 结构体数组存放待读取的消息 struct iovec { void * iov_base ; // 内容的地址 __kernel_size_t iov_len ; // 偏移量 }; [iovcnt]: struct iovec 结构体数组 的元素个数 【返回值】 成功返回读取的字节数 失败返回-1,同时 errno 被设置 使用 recv 读取 【头文件】 #include sys/types.h
#include sys/socket.h 【函数原型】 ssize_t recv(int sockfd, void *buf, size_t len, int flags); 【函数功能】 在套接字通信中和 read 函数类似不过多了第四个参数是一个发送标志如果没有其他特别用途一般指定为 0. 【参数含义】 [sockfd]: 通信套接字 [buf]:保存读取的内容 [len]: 读取内容的字节大小 [flags]: 读取标志没有特别用途一般为 0也可以是几个宏的组合值 【返回值】 成功返回实际读取的字节数 失败返回-1,同时 errno 被设置 【flags 读取标志选项】 [MSG_OOB] 接收以 out-of-band 送出的数据. [MSG_PEEK] 返回来的数据并不会在系统内删除, 如果再调用 recv()会返回相同的数据内容. [ MSG_WAITALL] 强迫接收到 len 大小的数据后才能返回, 除非有错误或信号产生 一般大流程 数据通信得时候需要使用 recv 函数指定该标志 [MSG_NOSIGNAL] 此操作不愿被 SIGPIPE 信号中断返回值成功则返回接收到的字符数, 失败返回-1,错误原因存于 errno 中 使用 recvfrom 读取 【头文件】 #include sys/types.h
#include sys/socket.h 【函数原型】 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen); 【函数功能】 在套接字通信中和 recv 函数类似不过多了两个参数用来保存发送者的协议地址和协议地址大小因为 UDP 是没有结果连接的所以一般使用该函数进行通信 【参数含义】 [sockfd]: 通信套接字 [buf]:保存读取的内容 [len]: 读取内容的字节大小 [flags]: 发送标志一般为 0也可以是几个宏的组合值 [dest_addr]:保存发送者的协议地址 [addrlen]:发送者协议地址的大小 【返回值】 成功返回实际读取的字节数 失败返回-1,同时 errno 被设置 【备注】 TCP 协议不支持这个函数 【示例】 // 读取服务器的回复消息 -UDP 读取 memset (buf, 0 , 1024 ); struct sockaddr_in src_addr ; // 保存消息发送方的地址 (IPport) memset ( src_addr, 0 , sizeof ( struct sockaddr_in)); // 清空结构体 socklen_t src_len sizeof ( src_addr ); // 保存可用大小 recvfrom (sockfd,buf, 1024 , 0 ,( struct sockaddr * ) src_addr , src_len ); 使用 recvmsg 读取 【头文件】 #include sys/types.h
#include sys/socket.h 【函数原型】 ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 【函数功能】 在套接字通信中和 recvfrom 函数类似不过 recvmsg 函数将发送的内容和接收者的协议地 址都放入了一个 struct msghdr 的结构体中。 【参数含义】 [sockfd]: 通信套接字 [msg]:保存了用于存储读取内容的空间地址和发送者协议地址等信息的结构体指针 struct msghdr { void * msg_name ; /* 发送 / 接收方的协议地址 */ socklen_t msg_namelen ; /* 地址数据长度 */ struct iovec * msg_iov ; /* 要发送 / 接收的数据向量 */ size_t msg_iovlen ; /* 向量中的元素数。 */ void * msg_control ; /* 辅助数据 ( 例如 BSD 文件传递 )*/ size_t msg_controllen ; /* 辅助数据缓冲区长度。 */ int msg_flags ; /* 接收到的消息上的标志。忽略 */ }; [flags]: 发送标志一般为 0也可以是几个宏的组合值 【返回值】 成功返回实际读取的字节数 失败返回-1,同时 errno 被设置 连接断开函数 shutdown 【头文件】 #include sys/socket.h 【函数原型】 int shutdown(int sockfd, int how); 【函数功能】 该函数可以选择关闭全双工连接的读通道或者写通道如果两个通道同时关闭则这个连接不能再继续通信。该只会关闭连接但是不会释放占用的文件描述符。 【参数含义】 [sockfd]: 待操作的套接字 [how]:操作选项可以选择以下三种 SHUT_RD 关闭读 SHUT_WR 关闭写 SHUT_RDWR 关闭读写 【返回值】 成功返回 0 失败返回-1,同时 errno 被设置 【备注】 close()函数会同时关闭全双工连接的读写通道除了关闭连接外还会释放套接字占用的文件描述符。而 shutdown()只会关闭连接但是不会释放占用的文件描述符。所以即使使用了 SHUT_RDWR 类型调用 shutdown()关闭连接也仍然要调用 close()来释放连接占用的文件描述 符。