• sengmsg()和recvmsg()的综合应用


    在一般的socket实现的时候,通常是用参数的形式,将文件描述符(FD)传到子进程或者直接传到read()汉书中。
    不过如果想以Socket的形式,来传送FD的话,那就要用到sendmsg和recvmsg函数了。关键点,FD的值要通过msg.msg_control来传递的,千万别写到传输用的buff里面,那样做只是简单的传值,没有任何意义的。
    /*
    -------------------------------------------------
    server
    -------------------------------------------------
    */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <fcntl.h>
    #include <ctype.h>
    #include <signal.h>
    #include <errno.h>
    #include <sys/wait.h>
    #include <sys/time.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <arpa/inet.h>
    #define PORT1 (u_short)11005
    #define PORT2 (u_short)11002
    /*
    -------------------------------------------------
    グローバル変数
    -------------------------------------------------
    */
    struct hostent *myhost;
    char hostname[257];
    char buff[257];
    struct sockaddr_in me;
    struct sockaddr_in aite;
    int sockfd;
    int fd = 0;
    int s_retry_counter;
    int ret;
    int status;
    int pid;
    int aiteaddrlen;
    fd_set l_fds;

    int sendmsg_fd;
    int recvmsg_fd;
    int rcv_proc();
    /*-------------------------------------------------
    メインルーチン
    -------------------------------------------------
    */
    int main () {
    int l_rtn;
    struct cmsghdr *l_cmsg;
    struct msghdr msg;
    struct iovec iov[1];
    int send_buf = 1;
    int l_length;
    char cms_data[sizeof(struct cmsghdr) + sizeof(int)];
    int l_fd_pair[2];
    if(socketpair(PF_UNIX, SOCK_STREAM, 0, l_fd_pair) != 0)
    {
    fprintf(stderr,"Create socketpair failed.\n");
    }
    pid = fork();
    switch(pid)
    {
    case -1: //エラー
    // 親側のソケットをクローズする
    fprintf(stderr,"fork() failled.\n");
    break;
    case 0: //子プロセス側
    close(l_fd_pair[0]);
    recvmsg_fd = l_fd_pair[1];
    rcv_proc();
    break;
    default: //親プロセス側
    close(l_fd_pair[1]);
    sendmsg_fd = l_fd_pair[0];
    break;
    }
    /*ソケットを作成*/
    if ((sockfd = socket(AF_INET, SOCK_STREAM , 0)) < 0 ) {
    fprintf(stderr,"Socket for server failed.\n");
    return -1;
    }
    /*自ホスト名の取得*/
    bzero(hostname,257);
    gethostname(hostname,256);
    /*自IPアドレスを取得*/
    if((myhost = gethostbyname(hostname)) == NULL) {
    fprintf(stderr,"bad hostname!\n");
    return -1;
    }
    /*自ホスト情報を構造体にセット*/
    bzero((char *)&me,sizeof(me));
    me.sin_family = AF_INET;
    me.sin_port = htons(PORT1);
    bcopy(myhost->h_addr, (char *)&me.sin_addr, myhost->h_length);

    /*BIND*/
    l_rtn = bind ( sockfd, (struct sockaddr *)&me, sizeof(me));
    if( l_rtn == -1)
    {
    fprintf(stderr, "Server could not bind.\n");
    return -1;
    }
    printf("Successfully bound in PORT1 %u.\n",PORT1);
    /*listen*/
    if ( (listen ( sockfd , 5)) == -1) {
    fprintf(stderr, "Listen failed.\n");
    return -1;
    }
    /*
    -------------------------------------------------
    ACCEPT
    -------------------------------------------------
    */
    s_retry_counter=0;
    fd = 0;
    while(1) {
    /* FD_ZERO( &l_fds );
    FD_SET(sockfd, &l_fds );
    l_rtn = select( sockfd+1, &l_fds, NULL, NULL, NULL);
    if(l_rtn == -1)
    {
    fprintf(stderr,"Select error !!\n");
    return -1;
    }

    if( FD_ISSET(sockfd, &l_fds) )
    {
    */
    /* acceptを試みる */
    aiteaddrlen = sizeof(aite);
    fd = accept( sockfd, ( struct sockaddr * )&aite , &aiteaddrlen);
    /* accept失敗 */
    if (fd == -1) {
    fprintf(stderr,"Accept failed.\n");
    return -1;
    }
    printf("accept fd : %d\n", fd);
    // send_buf = fd;

    l_length = sizeof(struct cmsghdr) + sizeof(int);
    l_cmsg = (struct cmsghdr*)cms_data;
    l_cmsg->cmsg_level = SOL_SOCKET;
    l_cmsg->cmsg_type = SCM_RIGHTS;
    l_cmsg->cmsg_len = l_length;

    bzero(&msg, sizeof(msg));
    msg.msg_name = NULL; /* attention this is a pointer to void* type */
    msg.msg_namelen = 0;
    iov[0].iov_base = &send_buf;
    iov[0].iov_len = sizeof(send_buf);
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_control = (caddr_t)l_cmsg;
    msg.msg_controllen = l_length;
    *(int *)CMSG_DATA(l_cmsg) = fd;
    printf("sendmsg begin. sendmsg_fd = %d\n", sendmsg_fd);
    l_rtn = sendmsg( sendmsg_fd, &msg, 0 );
    if(l_rtn == -1 )
    {
    fprintf(stderr,"Sendmsg failed. errno : %s\n",strerror(errno));
    return -1;
    }
    printf("Sendmsg Success!\n");
    // }

    }
    return 0;
    }
    /*
    =================================================
    子プロセス (s ソケット)
    正常終了:0 異常終了:-1
    =================================================
    */
    int rcv_proc()
    {
    int l_rtn;
    int cnt;
    int buff_size;
    struct msghdr msg;
    struct iovec iov[1];
    struct cmsghdr *cmsg_hdr;
    int cmsg_len;
    int recv_buf;
    int rcv_fd = 0;
    fd_set l_fds;
    // fd_set readok;
    int width;
    char recv_data[sizeof(struct cmsghdr) + sizeof(int)];
    cmsg_hdr = (struct cmsghdr*)recv_data;
    cmsg_len = sizeof(struct cmsghdr) + sizeof(int);
    printf("rcr_proc begin.\n");

    for(;;)
    { bzero(&msg, sizeof(msg));
    msg.msg_name = NULL; /* attention this is a pointer to void* type */
    msg.msg_namelen = 0;
    iov[0].iov_base = &recv_buf;
    iov[0].iov_len = sizeof(recv_buf);
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_control = (caddr_t)cmsg_hdr;
    msg.msg_controllen = cmsg_len;
    printf("recvmsg begin. recvmsg_fd = %d\n", recvmsg_fd);
    l_rtn = recvmsg( recvmsg_fd, &msg, 0);
    if(l_rtn == -1 )
    {
    fprintf(stderr,"Recvmsg failed. errno : %s\n", strerror(errno));
    return -1;
    }
    printf("Recvmsg Success!\n");
    rcv_fd = *((int *)CMSG_DATA(cmsg_hdr));
    FD_ZERO(&l_fds);
    FD_SET(rcv_fd, &l_fds);
    width = rcv_fd + 1;
    /*
    readok = l_fds;
    l_rtn = select(width, &readok, NULL, NULL, NULL);
    if(l_rtn == -1){
    fprintf(stderr,"Selete failed. errno : %s\n", strerror(errno));
    //return -1;
    }
    if( FD_ISSET(rcv_fd, (fd_set *)&readok) )
    {
    */
    printf("read fd : %d\n", rcv_fd);
    printf("read() begin.\n");
    bzero(buff,257);
    buff_size = read ( rcv_fd, buff, 256 );
    printf("buff_size : %d\n", buff_size);

    if(buff_size == -1){
    fprintf(stderr, "Read failed. errno : %s\n", strerror(errno));
    return -1;
    }
    printf("Received buffer : ");
    for (cnt=0; cnt< buff_size; cnt++) {
    putchar(buff[cnt]);
    }
    // }
    }
    return 1;
    }
    /*
    -------------------------------------------------
    client
    -------------------------------------------------
    */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <fcntl.h>
    #include <ctype.h>
    #include <signal.h>
    #include <errno.h>
    #include <sys/wait.h>
    #include <sys/time.h>
    #include <unistd.h>
    #define PORT (u_short)11005
    /*
    -------------------------------------------------
    グローバル変数
    -------------------------------------------------
    */
    char hostname[257];
    char buff[257];
    struct hostent *connect_host;
    struct sockaddr_in desthost;
    int s_listen;
    int s;
    int s_retry_counter;
    int ret;
    int status;
    int pid;
    int portno;
    /*
    -------------------------------------------------
    メインルーチン
    -------------------------------------------------
    */
    int main () {
    /*接続先ホスト名設定*/
    bzero(hostname,257);
    strcpy(hostname,"127.0.0.1");
    /*接続先IPアドレス取得*/
    if((connect_host = gethostbyname(hostname)) == NULL) {
    fprintf(stderr,"bad hostname!\n");
    return -1;
    }
    /*接続先情報をソケット型構造体にセット*/
    bzero((char *)&desthost,sizeof(desthost));
    desthost.sin_family = AF_INET;
    desthost.sin_port = htons(PORT);
    bcopy(connect_host->h_addr, (char *)&desthost.sin_addr, connect_host->h_length);
    /*ソケットを作成*/
    if ((s_listen = socket(AF_INET, SOCK_STREAM,0)) < 0 ) {
    fprintf(stderr,"Socket for client failed.\n");
    return -1;
    }
    /*コネクト*/
    if (connect(s_listen, ( struct sockaddr * )&desthost , sizeof(desthost) ) == -1) {
    fprintf(stderr,"Connect failed.\n");
    return -1;
    }
    /*文字列送信*/
    bzero(buff,257);
    strcpy(buff,"Test ABC.\n");
    if ( write(s_listen, buff, 256 ) == -1 ) {
    fprintf(stderr,"Write failed.\n");
    return -1;
    }
    /*ソケット切断*/
    close(s_listen);
    /*終了*/
    return 0;
    }

  • 相关阅读:
    UVALive
    训练指南 UVA
    训练指南 UVALive
    Codeforces Round #535 (Div. 3)
    训练指南 UVALive
    训练指南 UVALive
    Codeforces Round #534 (Div. 2)
    Codeforces Round #532 (Div. 2)
    《算法问题实战策略》——chaper9——动态规划法技巧
    《训练指南》——8.3
  • 原文地址:https://www.cnblogs.com/hnrainll/p/2141482.html
Copyright © 2020-2023  润新知