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;}


 

 

0 0