send_recv_writev_readv
来源:互联网 发布:java后端开发教程 编辑:程序博客网 时间:2024/05/18 22:13
send与recv
原型:
ssize_t send(int sockfd, const void *buf,size_t nbytes, int flags);
ssize_t recv(int sockfd, const void *buf,size_t nbytes, int flags);
最后一个参数可取值
MSG_OOB 发送/接收带外数据(out-of-banddata);
MSG_PEEK 返回来的数据并不会在系统内删除,如果再调用,recv()会返回相同的数据内容;
MSG_WAITALL 强迫收到地三个参数所指定的大小的数据后才返回,除非有错误或者信号产生;
MSG_DONTWAIT 调用I/O函数时不阻塞
MSG_NISIGNAL 此操作不愿被SIGPIPE信号中断
注:MSG_OOB用于发送”带外数据”紧急消息,实际上TCP不存在真正意义上的”带外数据”,真正意义上的带外数据是通过单独的通信路径告诉传输的消息,但是TCP不另外提供这种通道。只是使用紧急模式传输,其意义在于督促数据接收对象尽快处理数据,TCP的”顺序传输”特性依然成立
示例:
服务器端
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <netinet/in.h>#include <sys/socket.h>#include <signal.h>#include <fcntl.h>#define BUF_SIZE 30void error_handling(const char *message);void urg_handler(int signo);int acpt_sock;int recv_sock;int main(int argc, const char * argv[]) { struct sockaddr_in recv_adr, serv_adr; int str_len, state; socklen_t serv_adr_sz; struct sigaction act; char buf[BUF_SIZE]; if( 2 !=argc ) { printf("Usage: %s <port> \n", argv[0]); exit(1); } act.sa_handler = urg_handler; //windows下使用select处理,并且OOB数据属于异常 sigemptyset(&act.sa_mask); act.sa_flags = 0; acpt_sock = socket(PF_INET, SOCK_STREAM, 0); memset(&recv_adr, 0, sizeof(recv_adr)); recv_adr.sin_family = AF_INET; recv_adr.sin_addr.s_addr = htonl(INADDR_ANY); recv_adr.sin_port = htons(atoi(argv[1])); if( -1 == bind(acpt_sock, (struct sockaddr *) &recv_adr, sizeof(recv_adr)) ) error_handling("bind() error"); if( -1 == listen(acpt_sock, 5) ) error_handling("listen() error"); serv_adr_sz = sizeof(serv_adr); recv_sock = accept(acpt_sock, (struct sockaddr *)&serv_adr, &serv_adr_sz); //文件描述符recv_sock所指向的套接字触发的SIGURG信号由进程ID为getpid()的返回值的进程处理,特别是多进程的时候需要设置由谁处理 fcntl(recv_sock, F_SETOWN, getpid()); state = sigaction(SIGURG, &act, 0); //收到MSG_OOB紧急消息时,操作系统将产生SIGURG,并调用注册的处理函数 while (0 != (str_len = recv(recv_sock, buf, sizeof(buf), 0)) )//循环接收普通消息 { if( -1 == str_len ) continue; buf[str_len] = 0; puts(buf); } close(recv_sock); close(acpt_sock); return 0;}void urg_handler(int signo){ int str_len; char buf[BUF_SIZE]; str_len = recv(recv_sock, buf, sizeof(buf) - 1, MSG_OOB);//接收MSG_OOB紧急消息 buf[str_len] = 0; printf("Urgent message : %s \n", buf);}void error_handling(const char *message){ fputs(message, stderr); fputc('\n', stderr); exit(1);}
客户端
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#define BUF_SIZE 30void error_handling(const char *message);int main(int argc, const char * argv[]) { int sock; struct sockaddr_in recv_adr; if( 3 != argc ) { printf("Usage: %s <IP> <port> \n", argv[0]); exit(1); } sock = socket(PF_INET, SOCK_STREAM, 0); if( -1 == sock ) error_handling("socket() error"); memset(&recv_adr, 0, sizeof(recv_adr)); recv_adr.sin_family = AF_INET; recv_adr.sin_addr.s_addr = inet_addr(argv[1]); recv_adr.sin_port = htons(atoi(argv[2])); if( -1 == connect(sock, (struct sockaddr *) &recv_adr, sizeof(recv_adr)) ) error_handling("connect() error"); write(sock, "123", strlen("123"));//发送普通消息 send(sock, "4", strlen("4"), MSG_OOB);//发送紧急消息 write(sock, "567", strlen("567")); send(sock, "890", strlen("890"), MSG_OOB); close(sock); return 0;}void error_handling(const char *message){ fputs(message, stderr); fputc('\n', stderr); exit(1);}
writev与readv
通过函数writev可以将多个buf中的数据整合后写入套接字的输出缓冲区一并发送,调用readv函数可以使用多个buf分别接收输入缓冲区中的数据,因此适当使用这两个函数会减少I/O函数调用次数,而且在没开启Nagle算法时,使用函数writev相比较于使用函数write很可能会减少数据包个数,故使用这两个函数有助于提高数据通信效率
writev函数
ssize_t writev(int filedes, const structiovec *iov, int iovcnt);//成功返回发送字节数,失败返回-1
参数一: 数据传递目标的文件描述符,可以是套接字、文件或标准输出描述符
参数二: 指向iovec结构体数组的指针,结构体中包含待发送数据的地址和待发送数据大小
参数三: 第二个参数中结构体数组的长度
结构体iovec
struct iovec
{
void *iov_base; /* Starting address*/
size_t iov_len; /* Length in bytes */
};
示例:
#include <stdio.h>#include <sys/uio.h>int main(int argc, const char * argv[]) { struct iovec vec[2]; char buf1[] = "ABCDEFG"; char buf2[] = "1234567"; int str_len; vec[0].iov_base = buf1;//待传输位置 vec[0].iov_len = 3;//带传输大小 vec[1].iov_base = buf2; vec[1].iov_len = 4; str_len = writev(1, vec, 2); //1为标准输出 puts(""); printf("Write bytes: %d \n", str_len); return 0;}
readv函数
ssize_t readv(int filedes, const structiovec *iov, int iovcnt); //成功返回接受字节数,失败返回-1
示例:
#include <stdio.h>#include <sys/uio.h>#define BUF_SIZE 100int main(int argc, const char * argv[]) { struct iovec vec[2]; char buf1[BUF_SIZE] = { 0 }; char buf2[BUF_SIZE] = { 0 }; int str_len; vec[0].iov_base = buf1;//意图存储数据的位置0 vec[0].iov_len = 5;//位置0意图存储的最大字节数为5,剩余数据由下一个位置(位置1)存储 vec[1].iov_base = buf2;//位置1 vec[1].iov_len = BUF_SIZE; str_len = readv(0, vec, 2); //0位标准输入 printf("Read bytes: %d \n", str_len); printf("First message: %s \n", buf1); printf("Second message: %s \n", buf2); return 0;}
- send_recv_writev_readv
- LeetCode 418. Sentence Screen Fitting 调整屏幕上的句子
- Android之懒人框架 ButterKnife 8.4添加使用
- Java PAT练习1.0
- Android自定义星星评分控件,高效
- 204. Count Primes
- send_recv_writev_readv
- LeetCode 449. Serialize and Deserialize BST
- MYSQL5.5的手动编译安装
- 7. Reverse Integer 一个简单但是非常考察思维全面性的题目。
- C++实现窗口显示在最前面的代码
- Python Unicode 基本知识
- Viewpager使用时注意的东西
- 构建知识图谱,让自己更值钱
- 263. Ugly Number