13.1 send & recv函数

13.1.1 Linux中的send & recv

  1. #include<sys/socket.h>
  2. ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);
  3. //成功时返回发送的字节数,失败时返回-1
  4. //sockfd 表示数据传输对象的连接的套接字文件描述符
  5. //buf 保存待传输数据的缓冲地址值
  6. //nbytes 待传输的字节数
  7. //flags 传输数据时指定的可选项信息
#include<sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
//成功时返回接收的字节数,失败时返回-1
//sockfd表示数据接收对象的连接套接字文件描述符
//buf保存接收文件的缓冲地址值
//nbytes可接收的最大字节数
//flags接收数据时指定的可选信息项
可选项 含义 send recv
MSG_OOB 用于传输带外数据 * *
MSG_PEEK 验证输入缓冲中是否存在接收的数据 *
MSG_DONTROUTE 数据传输过程中不参照路由表,在本地网络中寻找目的地 *
MSG_DONTWAIT 调用I/O函数时不阻塞,用于使用非阻塞I/O * *
MSG_WAITALL 防止函数返回,直到接收全部请求的字节数 *

13.1.2 MSG_OOB:发送紧急消息

//oob_send.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>

#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, char *argv[])
{
    int sock;
    struct sockaddr_in recv_adr;
    if(argc!=3){
        printf("Usage: %s <IP> <port>\n",argv[0]);
        exit(1);
    }

    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=inet_addr(argv[1]);
    recv_adr.sin_port=htons(atoi(argv[2]));

    if(connect(sock, (struct sockaddr*)&recv_adr, sizeof(recv_adr))==-1)
        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(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}
//oob_recv.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<fcntl.h>

#define BUF_SIZE 30
void error_handling(char *message);
void urg_handler(int signo);

int acpt_sock;
int recv_sock;

int main(int argc, 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(argc!=2){
        printf("Usage: %s <port>\n", argv[0]);
        exit(1);
    }

    act.sa_handler=urg_handler;
    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(bind(acpt_sock, (struct sockaddr*)&recv_adr, sizeof(recv_adr))==-1)
        error_handling("bind() error");
    listen(acpt_sock, 5);

    serv_adr_sz=sizeof(serv_adr);
    recv_sock=accept(acpt_sock, (struct sockaddr*)&serv_adr, &serv_adr_sz);

    fcntl(recv_sock, F_SETOWN, getpid());
    state=sigaction(SIGURG, &act, 0);

    while((str_len=recv(recv_sock, buf, sizeof(buf), 0))!=0)
    {
        if(str_len==-1)
            continue;
        buf[str_len]=0;
        puts(buf);
    }
    close(recv_sock);
    close(recv_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);
    buf[str_len]=0;
    printf("Urgent message: %s \n", buf);
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

13.1.3 检查输入缓冲

//peek_send.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
void error_handling(char *message);

int main(int argc, char *argv[])
{
    int sock;
    struct sockaddr_in send_adr;
    if(argc!=3){
        printf("Usage: %s <IP> <port>\n",argv[0]);
        exit(1);
    }

    sock=socket(PF_INET, SOCK_STREAM, 0);
    memset(&send_adr, 0, sizeof(send_adr));
    send_adr.sin_family=AF_INET;
    send_adr.sin_addr.s_addr=inet_addr(argv[1]);
    send_adr.sin_port=htons(atoi(argv[2]));

    if(connect(sock, (struct sockaddr*)&send_adr, sizeof(send_adr))==-1)
        error_handling("connect() error!");

    write(sock, "123", strlen("123"));
    close(sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}
//peek_recv.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, char *argv[])
{
    int acpt_sock, recv_sock;
    struct sockaddr_in acpt_adr, recv_adr;
    int str_len, state;
    socklen_t recv_adr_sz;
    char buf[BUF_SIZE];
    if(argc!=2){
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }

    acpt_sock=socket(PF_INET, SOCK_STREAM, 0);
    memset(&acpt_adr, 0, sizeof(acpt_adr));
    acpt_adr.sin_family=AF_INET;
    acpt_adr.sin_addr.s_addr=htonl(INADDR_ANY);
    acpt_adr.sin_port=htons(atoi(argv[1]));

    if(bind(acpt_sock, (struct sockaddr*)&acpt_adr, sizeof(acpt_adr))==-1)
        error_handling("bind() error");
    listen(acpt_sock, 5);

    recv_adr_sz=sizeof(recv_adr);
    recv_sock=accept(acpt_sock, (struct sockaddr*)&recv_adr, &recv_adr_sz);

    while(1)
    {
        str_len=recv(recv_sock, buf, sizeof(buf)-1, MSG_PEEK|MSG_DONTWAIT);
        if(str_len>0)
            break;
    }

    buf[str_len]=0;
    printf("Buffering %d bytes: %s \n", str_len, buf);

    str_len=recv(recv_sock, buf, sizeof(buf)-1, 0);
    buf[str_len]=0;
    printf("Read again: %s \n", buf);
    close(acpt_sock);
    close(recv_sock);

    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

13.2 readv & writev 函数

13.2.1 使用readv & writev函数

writev函数可以将分散保存在多个缓冲中的数据一并发送,通过readv函数可以由多个缓冲分别接收。

#include<sys/uio.h>

ssize_t writev(int filedes, const struct iovec *iov, int ivocnt);
//成功时返回发送的字节数,失败时返回-1
//filedes表示数据传输对象的套接字文件描述符。但该函数并不只限于套接字,因此,可以像read函数一样向其传递文件或标准输出描述符
//iov iovec结构体数组的地址值,结构体iovec中包含待发送的数据的位置和大小信息
//iovcnt向第二个参数传递数组的长度
struct iovec
{
    void *iov_base;//缓冲地址
    size_t iov_len;//缓冲大小
}
//writev.c
#include<stdio.h>
#include<sys/uio.h>

int main(int argc, 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);
    puts("");
    printf("Write bytes: %d \n", str_len);
    return 0;
}
//readv.c
#include<stdio.h>
#include<sys/uio.h>
#define BUF_SIZE 100

int main(int argc, char *argv[])
{
    struct iovec vec[2];
    char buf1[BUF_SIZE]={0,};
    char buf2[BUF_SIZE]={0,};
    int str_len;

    vec[0].iov_base=buf1;
    vec[0].iov_len=5;
    vec[1].iov_base=buf2;
    vec[1].iov_len=BUF_SIZE;

    str_len=readv(0, vec, 2);
    printf("Read bytes: %d\n", str_len);
    printf("First message: %s \n", buf1);
    printf("Second message: %s \n", buf2);
    return 0;
}