Linux 网络编程基础(3) -- 数据的IO

首先介绍两个数据结构及相关的操作函数:struct iovec、struct msghdr

struct iovec {

  void * iov_base;    /*向量的缓冲地址*/

  size_t iov_len;   /*向量缓冲区的大小,以字节为单位*/

};

iovec定义在linux/include/uio.h中,此数据结构与readv()和writev()联合使用。

ssize_t readv(int s, const struct iovec *vector, int count);

返回值为成功接收的字节数。   s: 文件描述符         vector:iovec数组的起始地址                 count:iovec数组的元素个数。

ssize_t writev(int fd, const iovec *vector, int count);

返回值为成功发送的字节数。   fd:文件描述符         vector:发送数据的vector数组地址          count:iovec数组的元素个数

应用的例子:

/*
    服务器端代码
*/

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/uio.h>
#include <netinet/in.h>
#define Serv_Port  8888
#define BackLog 5
void process_client_vector(int sock_cli);

int  main(char *argv[], int argc)
{
    int sock_serv, sock_cli;
    struct sockaddr_in  server_addr;
    struct sockaddr_in  client_addr;
    
    int err;
    pid_t handle_client_pid;

    sock_serv = socket(AF_INET, SOCK_STREAM, 0);
    if(sock_serv < 0){
        printf("Error When build Socket
");
        return 1;
    }

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(Serv_Port);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    err = bind(sock_serv, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if(err < 0){
        printf("Error When Bind
");
        return 1;
    }

    err = listen(sock_serv, BackLog);
    if(err < 0){
        printf("Error When Listen
");
        return 1;
    }

//    while(1){
        int addrlen = sizeof(struct sockaddr);
        printf("Waiteing... ...
");
        sock_cli = accept(sock_serv, (struct sockaddr*)&client_addr, &addrlen);

        if(sock_cli < 0)
            ;//continue;
        handle_client_pid = fork();
        if(handle_client_pid == 0){
            close(sock_serv);
            process_client_vector(sock_cli);
        }
        else
            close(sock_cli);
//    }
}

void process_client_vector(int sock_cli)
{
    int number;
    char str;
    char ch;
    int i = 0;
    printf("One client is Accpted
");
    struct iovec *recv_vector = (struct iovec*)malloc(3*sizeof(struct iovec));

    if(!recv_vector){
        printf("NO Enough Space Here
");
        return;
    }

    recv_vector[0].iov_base = &number;
    recv_vector[0].iov_len = sizeof(number);
    
    recv_vector[1].iov_base = &str;
    recv_vector[1].iov_len = sizeof(str);
    
    recv_vector[2].iov_base = &ch;
    recv_vector[2].iov_len = sizeof(ch);

    ssize_t size = readv(sock_cli, recv_vector, 3);
    printf("RECVED: Number%d  STR: %c   CHAR:%c
",number,str,ch);

}
/*
    客户器端代码
*/

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/uio.h>
#include <netinet/in.h>

#define Serv_Port 8888
void process_server_vector(int sock_cli);

int main(char *argv[], int argc)
{
    struct sockaddr_in server_addr;
    int err;
    int sock_cli;

    sock_cli = socket(AF_INET, SOCK_STREAM, 0);
    if(sock_cli < 0){
        printf("Error When Socket()
");
        return 1;
    }

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(Serv_Port);
    inet_pton(AF_INET, "127.0.0.1",&server_addr.sin_addr);

    connect(sock_cli, (struct sockaddr *)&server_addr, sizeof(server_addr));

    process_server_vector(sock_cli);

    close(sock_cli);

    return 0;
}

void process_server_vector(int sock_cli)
{
    int number = 10;
    char str = 'K';
    char ch = 'M';
    ssize_t size = 0;

    struct iovec *vector = (struct iovec *)malloc(3*sizeof(struct iovec));

    vector[0].iov_base = &number;
    vector[0].iov_len = sizeof(number);
    
    vector[1].iov_base = &str;
    vector[1].iov_len = sizeof(str);
    
    vector[2].iov_base = &ch;
    vector[2].iov_len = sizeof(ch);

    size = writev(sock_cli, vector, 3);
    if(size < 0 )
        printf("Writev Error
");
}

 msghdr 结构体定义在linux/include/socket.h中

 struct msghdr {
          void            *msg_name;      /* ptr to socket address structure */
          int             msg_namelen;    /* size of socket address structure */
          struct iovec    *msg_iov;       /* scatter/gather array */
          __kernel_size_t msg_iovlen;     /* # elements in msg_iov */
          void            *msg_control;   /* ancillary data */
          __kernel_size_t msg_controllen; /* ancillary data buffer length */
          unsigned int    msg_flags;      /* flags on received message */
  };

这个数据结构如果不考虑msg_falsgs,与struct iovec的用法并没有很大的差别,操作这个数据结构的函数:
#include<sys/uio.h>
ssize_t recvmsg(int s, const struct msghdr *msg, int flags);
s: 套接字 msg:承接数据的消息数据结构 flags:没有很大的意义,
ssize_t sendmsg(int s, const struct msghdr *msg, int flags );
s: 套接字             msg:承接数据的消息数据结构   flags:决定以什么方式发送数据
readmsg的接收方式取决于msg结构中msg_flags的值,这也是readmsg()与函数sendmsg()的不同的地方,sendmsg()函数的发送方式有参数决定。

在没有介绍套接字的选项前,先不对msghdr的相关代码编写进行实践,因为msghdr中的msg_name,msg_control,msg_flags 等成员的设定与当前使用的协议是相关的,待以后把套接字的选项介绍完后,在深入探究msghdr的使用。

除了上述介绍的几个函数,还有很多的IO函数,现总结如下:



int read(int fd, void * buffer, int nbyte);
int write(int handle, void *buf, int nbyte);
这两个函数可以用于任何的描述符,可以用于文件,标准输入输出,和套接字。

readv(), writev(),recvmsg(),sendmsg()的具体函数参考上面的具体内容。

int recvfrom(int s,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen);
s: 套接字  buf:数据接收缓冲区  len:接收数据长度 flags:是以下一个或者多个标志的组合体,可通过or操作连在一起
from:数据的来源的地址 fromlen: 地址长度。

 
原文地址:https://www.cnblogs.com/tju-gsp/p/3655015.html