9 高级IO函数

套接字超时

1、调用alarm,指定超时时产生SIGALRM信号,捕捉该信号。注意信号处理在多线程上处理有困难,建议在单进程、单线程的程序使用信号

2、通过select,通过设置select内置超时。

3、使用SO_RCVTIMEO和SO_SNDTIMEO套接字选项。

1、2中方法可以用于各种描述符,不仅仅套接字描述符,而第3种只能用于套接字;第1种可以用于connect函数,2、3不能;第3种,一旦超时,send或recv会返回EWOULDBLOCK。


recvmsg和sendmsg函数

9 高级IO函数_第1张图片

9 高级IO函数_第2张图片

9 高级IO函数_第3张图片

9 高级IO函数_第4张图片

msg_name获取的对端地址信息,msg_control填充的是本端地址信息。

第3个参数flag取值如下表所示:

9 高级IO函数_第5张图片

msghdr中msg_flags取值如下表所示:

9 高级IO函数_第6张图片

9 高级IO函数_第7张图片

总结:在这些flag中,MSG_DONTWAIT表示本次读取实现异步,MSG_PEEK读取数据,但是同时并不将其从接收队列中减少。

9 高级IO函数_第8张图片


sendmsg 和 recvmsg例子


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /*for struct sockaddr_in*/

#define SVR_IP      "127.0.0.1"
#define SVR_PORT    1234
#define BUFSIZE	    255

int main()
{
	int ret     = 0;
	int sockfd  = 0;
    struct sockaddr_in svr_addr;
    memset(&svr_addr, 0, sizeof(struct sockaddr_in));

    // create client socket fd
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd == -1) {
		perror("socket failed");
		exit(1);
	}
    
    // connet to server
	svr_addr.sin_family         = AF_INET;                 
	svr_addr.sin_port           = htons(SVR_PORT);          
	svr_addr.sin_addr.s_addr    = inet_addr(SVR_IP); 
    ret = connect(sockfd, (struct sockaddr *)&svr_addr, sizeof(struct sockaddr_in));
	if (ret == -1) {
		perror("connect failed");
		exit(1);
	}

    

    int i = 0;
    for (i = 0; i < 150; i++)
    {
        char * msghead = "msg header...";
        char * msgbody = "msg body...";


        struct msghdr msg;
        struct iovec  iov[2];
        memset(&msg, 0, sizeof(msg));
        iov[0].iov_base = msghead;
        iov[0].iov_len  = strlen(msghead);
        printf("send header msg: %s\n", msghead);
        iov[1].iov_base = msgbody;
        iov[1].iov_len  = strlen(msgbody);
        printf("send body msg: %s\n", msgbody);
        msg.msg_iov     = iov;
        msg.msg_iovlen  = 2;
        
        if (sendmsg(sockfd, &msg, 0) < 0) {
            perror("sendmsg()");
        }
        
        char recv_buf[BUFSIZE] = {0};
        int recv_len = recv(sockfd, recv_buf, sizeof(recv_buf), 0);
        printf("client recv msg: %s%d\n", recv_buf, recv_len);

        sleep(1);
    }   

    close(sockfd);
}


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/queue.h>

#define MYPORT          1234    // the port users will be connecting to
#define BACKLOG         512     // how many pending connections queue will hold
#define BUF_SIZE        1024
#define MAX_PATH_LEN    255

#ifndef bool
    #define bool int
#endif

#define FALSE 0
#define TRUE  1


int main(void)
{    
    int ret    = 0; 
    int udp_fd = 0; // udp socket fd

    struct sockaddr_in server_addr; // server address information
    memset(&server_addr, 0, sizeof(struct sockaddr_in));

    udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == udp_fd) 
    {
        perror("socket");
        return -1;
    }

    bzero(&server_addr, sizeof(struct sockaddr_in));
    server_addr.sin_family      = AF_INET;        // host byte order
    server_addr.sin_port        = htons(MYPORT);  // short, network byte order
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);     // automatically fill with my IP
    memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));

    ret = bind(udp_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (-1 == ret) 
    {
        perror("bind");
        return -1;
    }

    while (1) 
    {
        struct sockaddr_in cli_addr;
        memset(&cli_addr, 0, sizeof(struct sockaddr_in));
        
        char msghead[13] = {0};
        char msgbody[11] = {0};
        
        struct iovec  iov[2];
        iov[0].iov_base = msghead;
        iov[0].iov_len  = 13;
        iov[1].iov_base = msgbody;
        iov[1].iov_len  = 11;
        
        struct msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_name    = &cli_addr;
        msg.msg_namelen = sizeof(struct sockaddr_in);
        msg.msg_iov     = iov;
        msg.msg_iovlen  = 2;
        
        if (recvmsg(udp_fd, &msg, 0) < 0) {
            perror("sendmsg()");
        }


        printf("recv header msg: %s\n", msghead);
        printf("recv body msg: %s\n", msgbody);

        sendto(udp_fd, msgbody, 11, 0, (struct sockaddr *)&cli_addr, sizeof(struct sockaddr_in));
#if 0        
        char msg[BUF_SIZE] = {0};
        struct sockaddr_in cliaddr;
        socklen_t len = sizeof(struct sockaddr_in);
        ssize_t n = recvfrom(udp_fd, msg, BUF_SIZE, 0, (struct sockaddr *)&cliaddr, &len);
        printf("udp recv: %s\n", msg);
        printf("udp send: %s\n", msg);
        sendto(udp_fd, msg, n, 0, (struct sockaddr *)&cliaddr, len);
#endif
    }
}


辅助数据:

9 高级IO函数_第9张图片


msg_controllen是整个辅助数据的总长度,在msg_control执行的内存,会有填充数据,系统为了对于用户屏蔽填充数据,提供了如下宏:

9 高级IO函数_第10张图片

使用方法如下:

9 高级IO函数_第11张图片

其中CMSG_LEN返回实际数据长度,不包括填充数据,CMSG_SPACE则包括填充数据。

你可能感兴趣的:(9 高级IO函数)