当前位置:   article > 正文

进程笔记2:进程之间的通信(UNIX域套接字socket) ._socket(af_unix, sock_dgram, 0)

socket(af_unix, sock_dgram, 0)

socket的地址数据结构根据不同的系统以及网络环境有不同形式。为了使不同格式地址能够被传入套接字函数,必须强制将地址结构转换为:

  1. struct sockaddr{  
  2.    sa_family_t sa_family; /* address family*/  
  3.    char        sa_data[]; /* variable-length address*/  
  4.    ...  
  5. };  
  1. struct sockaddr{
  2. sa_family_t sa_family; /* address family*/
  3. char sa_data[]; /* variable-length address*/
  4. ...
  5. };

套接字实现可以自由地添加额外的成员并且定义sa_data成员的大小。例如在linux中,该结构定义如下

  1. struct sockaddr{  
  2.    sa_family_t sa_family;   /* address family*/  
  3.    char        sa_data[14]; /* variable-length address*/  
  4. };  
  1. struct sockaddr{
  2. sa_family_t sa_family; /* address family*/
  3. char sa_data[14]; /* variable-length address*/
  4. };

其中sa_family_t表示套接字的通信域。主要有以下四个值


描述
AF_INETIPv4因特网域
AF_INET6IPv6因特网域
AF_UNIXUNIX域
AF_UNSPEC未指定


创建套接字的函数如下

  1. #include <sys/socket.h>   
  2. int socket(int domain, int type, int protocol);/*成功返回文件(套接字)描述符,出错返回-1  
  1. #include <sys/socket.h>
  2. int socket(int domain, int type, int protocol);/*成功返回文件(套接字)描述符,出错返回-1

其中domain指代通信域,type指代套接字类型,主要有以下四种

类型描述
SOCK_DGRAM长度固定的、无连接的不可靠报文传递
SOCK_RAMIP协议的数据报接口
SOCK_SEQPACKET长度固定、有序、可靠的面向连接报文传递
SOCK_STREAM有序、可靠、双向的面向连接字节流

参数protocol通常是零,表示按给定的域和套接字类型选择默认协议。当对同一域和套接字类型支持多个协议时,可以使用protocol参数选择一个特定协议。

一个多进程间利用UNIX域套接字(只用在本地)进行通信的例子( 代码分两部分不方便观察,后面socket_unix.c将其合为了一部分

  1.  /* 
  2. domain_socket.h 
  3. @Author: duanjigang @2006-4-11 
  4. @Desp: declaratin of methods used for unix-domain-socket communication  
  5. */  
  6. #ifndef _H_   
  7. #define _H_   
  8. #include <stdio.h>   
  9. #include <unistd.h>   
  10. #include <sys/un.h>   
  11. #include <sys/socket.h>   
  12. #define MSG_SIZE 1024   
  13. int init_send_socket(struct sockaddr_un * addr,char * path)  
  14. {  
  15.         int sockfd,len;  
  16.         sockfd=socket(AF_UNIX,SOCK_DGRAM,0);  
  17.         if(sockfd<0)  
  18.         {  
  19.                 exit(1);  
  20.         }  
  21.         bzero(addr,sizeof(struct sockaddr_un));  
  22.         addr->sun_family=AF_UNIX;  
  23.         strcpy(addr->sun_path,path);  
  24.         return sockfd;  
  25. }  
  26. int init_recv_socket(char * path)  
  27. {  
  28.         int sockfd,len;   
  29.         struct sockaddr_un addr;   
  30.         sockfd=socket(AF_UNIX,SOCK_DGRAM,0);   
  31.         if(sockfd<0)   
  32.         {   
  33.            return -1;  
  34.         }   
  35.         bzero(&addr,sizeof(struct sockaddr_un));   
  36.         addr.sun_family = AF_UNIX;   
  37.         strcpy(addr.sun_path, path);  
  38.         unlink(path);  
  39.         len = strlen(addr.sun_path) + sizeof(addr.sun_family);  
  40.         if(bind(sockfd,(struct sockaddr *)&addr,len)<0)   
  41.          {   
  42.           return -1;  
  43.          }   
  44.         return sockfd;  
  45.   
  46. }  
  47. int receive_from_socket(int sockfd, char msg[])  
  48. {  
  49.       int n;   
  50.       memset(msg, 0, MSG_SIZE);  
  51.       n=recvfrom(sockfd, msg, MSG_SIZE, 0, NULL, NULL);   
  52.       if(n<=0)  
  53.       {  
  54.        return -1;  
  55.       }  
  56.       msg[n]=0;  
  57.       return n;  
  58. }  
  59. int send_to_socket(int sockfd, char msg[], const struct sockaddr_un * addr)  
  60. {  
  61.         int len;   
  62.         len = strlen(addr->sun_path)+sizeof(addr->sun_family);  
  63.         sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)addr,len);   
  64.         return 1;  
  65. }  
  66. #endif  
  1. /*
  2. domain_socket.h
  3. @Author: duanjigang @2006-4-11
  4. @Desp: declaratin of methods used for unix-domain-socket communication
  5. */
  6. #ifndef _H_
  7. #define _H_
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <sys/un.h>
  11. #include <sys/socket.h>
  12. #define MSG_SIZE 1024
  13. int init_send_socket(struct sockaddr_un * addr,char * path)
  14. {
  15. int sockfd,len;
  16. sockfd=socket(AF_UNIX,SOCK_DGRAM,0);
  17. if(sockfd<0)
  18. {
  19. exit(1);
  20. }
  21. bzero(addr,sizeof(struct sockaddr_un));
  22. addr->sun_family=AF_UNIX;
  23. strcpy(addr->sun_path,path);
  24. return sockfd;
  25. }
  26. int init_recv_socket(char * path)
  27. {
  28. int sockfd,len;
  29. struct sockaddr_un addr;
  30. sockfd=socket(AF_UNIX,SOCK_DGRAM,0);
  31. if(sockfd<0)
  32. {
  33. return -1;
  34. }
  35. bzero(&addr,sizeof(struct sockaddr_un));
  36. addr.sun_family = AF_UNIX;
  37. strcpy(addr.sun_path, path);
  38. unlink(path);
  39. len = strlen(addr.sun_path) + sizeof(addr.sun_family);
  40. if(bind(sockfd,(struct sockaddr *)&addr,len)<0)
  41. {
  42. return -1;
  43. }
  44. return sockfd;
  45. }
  46. int receive_from_socket(int sockfd, char msg[])
  47. {
  48. int n;
  49. memset(msg, 0, MSG_SIZE);
  50. n=recvfrom(sockfd, msg, MSG_SIZE, 0, NULL, NULL);
  51. if(n<=0)
  52. {
  53. return -1;
  54. }
  55. msg[n]=0;
  56. return n;
  57. }
  58. int send_to_socket(int sockfd, char msg[], const struct sockaddr_un * addr)
  59. {
  60. int len;
  61. len = strlen(addr->sun_path)+sizeof(addr->sun_family);
  62. sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)addr,len);
  63. return 1;
  64. }
  65. #endif

  1. /* 
  2. main.c 
  3. @Author: duanjigang @ 2006-4-11 
  4. @Desp: Two processes communicate with unix domain socket 
  5. */  
  6. #include "domain_socket.h"   
  7. #define PATH "/home/useless"   
  8. /* 
  9. 进程间通过域进行通讯-举例:父子进程,一个发送,一个接收 
  10. */  
  11. int main(void)  
  12. {  
  13.   int pid;  
  14.   /* 
  15.   子进程用于发送消息 
  16.   */  
  17.   if((pid = fork()) == 0)  
  18.   {  
  19.     int fd, counter = 0;  
  20.     char send_buffer[MSG_SIZE];  
  21.     struct sockaddr_un addr;  
  22.     if( (fd = init_send_socket(&addr, PATH)) > 0)  
  23.     while(1)  
  24.     {  
  25.        memset(send_buffer, 0 , MSG_SIZE);  
  26.        /* 
  27.            防止计数器越界,所以做一个复位判断 
  28.            */  
  29.        sprintf(send_buffer,"message for %d times",counter++ >= 10000 ? 1 : counter);  
  30.        send_to_socket(fd, send_buffer, &addr);  
  31.        printf("Sender: %s\n", send_buffer);  
  32.        sleep(1);  
  33.     }  
  34.   }/* 
  35.    父进程用于接收消息 
  36.   */  
  37.   else  
  38.   {  
  39.       int fd;  
  40.       char recv_buffer[MSG_SIZE];  
  41.       if( (fd = init_recv_socket(PATH))> 0)  
  42.       while(1)  
  43.       {  
  44.        memset(recv_buffer, 0, MSG_SIZE);  
  45.        if(receive_from_socket(fd, recv_buffer))  
  46.        {  
  47.             printf("Receiver: %s\n", recv_buffer);  
  48.        }  
  49.       }  
  50.   }  
  51. }  
  52.    
  1. /*
  2. main.c
  3. @Author: duanjigang @ 2006-4-11
  4. @Desp: Two processes communicate with unix domain socket
  5. */
  6. #include "domain_socket.h"
  7. #define PATH "/home/useless"
  8. /*
  9. 进程间通过域进行通讯-举例:父子进程,一个发送,一个接收
  10. */
  11. int main(void)
  12. {
  13. int pid;
  14. /*
  15. 子进程用于发送消息
  16. */
  17. if((pid = fork()) == 0)
  18. {
  19. int fd, counter = 0;
  20. char send_buffer[MSG_SIZE];
  21. struct sockaddr_un addr;
  22. if( (fd = init_send_socket(&addr, PATH)) > 0)
  23. while(1)
  24. {
  25. memset(send_buffer, 0 , MSG_SIZE);
  26. /*
  27. 防止计数器越界,所以做一个复位判断
  28. */
  29. sprintf(send_buffer,"message for %d times",counter++ >= 10000 ? 1 : counter);
  30. send_to_socket(fd, send_buffer, &addr);
  31. printf("Sender: %s\n", send_buffer);
  32. sleep(1);
  33. }
  34. }/*
  35. 父进程用于接收消息
  36. */
  37. else
  38. {
  39. int fd;
  40. char recv_buffer[MSG_SIZE];
  41. if( (fd = init_recv_socket(PATH))> 0)
  42. while(1)
  43. {
  44. memset(recv_buffer, 0, MSG_SIZE);
  45. if(receive_from_socket(fd, recv_buffer))
  46. {
  47. printf("Receiver: %s\n", recv_buffer);
  48. }
  49. }
  50. }
  51. }

运行结果示例:

  1. Sender: message for 1 times  
  2.   
  3. Sender: message for 2 times  
  4.   
  5. Receiver: message for 2 times  
  6.   
  7. Sender: message for 3 times  
  8.   
  9. Receiver: message for 3 times  
  10.   
  11. Sender: message for 4 times  
  12.   
  13. Receiver: message for 4 times  
  14.   
  15. Sender: message for 5 times  
  16.   
  17. Receiver: message for 5 times  
  1. Sender: message for 1 times
  2. Sender: message for 2 times
  3. Receiver: message for 2 times
  4. Sender: message for 3 times
  5. Receiver: message for 3 times
  6. Sender: message for 4 times
  7. Receiver: message for 4 times
  8. Sender: message for 5 times
  9. Receiver: message for 5 times


socket_unix.c

  1. //利用UNIX域套接字通信   
  2.   
  3. #include <stdio.h>   
  4. #include <unistd.h>   
  5. #include <sys/un.h>   
  6. #include <sys/socket.h>   
  7.   
  8. #define MSG_MAX_SIZE 1024   
  9. #define PATH "a.socket"//套接字文件   
  10.   
  11. int main()  
  12. {  
  13.     int len;  
  14.     int socket_fd;  
  15.     struct sockaddr_un addr;  
  16.   
  17.     bzero(&addr, sizeof(struct sockaddr_un));  
  18.     addr.sun_family = AF_UNIX;  
  19.     strcpy(addr.sun_path, PATH);   
  20.     len = strlen(addr.sun_path)+sizeof(addr.sun_family);  
  21.       
  22.     if(!fork())//子进程内部代码   
  23.     {  
  24.         int counter = 0;  
  25.         char send_buffer[MSG_MAX_SIZE];  
  26.   
  27.         //init send socket   
  28.         socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);   
  29.         if(socket_fd<0)  
  30.         {  
  31.             printf("client socket error!");  
  32.             return 0;  
  33.         }  
  34.           
  35.         while(1) //循环发送数据消息   
  36.         {  
  37.             memset(send_buffer, 0, MSG_MAX_SIZE);  
  38.             sprintf(send_buffer, "message for %d times", counter++);  
  39.               
  40.             //将数据信息发送到addr指定的套接字文件之中,所以这样进程之间就可以进行通信   
  41.             sendto(socket_fd, send_buffer, strlen(send_buffer), 0, (struct sockaddr*)&addr, len);  
  42.   
  43.             printf("sender:%s\n", send_buffer);  
  44.             sleep(1);  
  45.         }  
  46.     }  
  47.     else  
  48.     {  
  49.         char recv_buffer[MSG_MAX_SIZE];  
  50.   
  51.         //init recv socket   
  52.         socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);  
  53.         if(socket_fd<0)  
  54.         {  
  55.             printf("server socket error!");  
  56.             return 0;  
  57.         }  
  58.           
  59.         unlink(PATH);//防止要创建的socket文件已存在   
  60.         if(bind(socket_fd, (struct sockaddr *)&addr, len)<0)//只有bind以后才会在硬盘创建套接字PATH   
  61.         {  
  62.             printf("bind error");  
  63.             return 0;  
  64.         }  
  65.   
  66.         while(1)//循环接收数据   
  67.         {  
  68.             memset(recv_buffer, 0, MSG_MAX_SIZE);  
  69.   
  70.             //receive from socket从指定socket中读取数据,这里socket已经绑定了指定的PATH的文件   
  71.             recvfrom(socket_fd, recv_buffer, MSG_MAX_SIZE, 0, NULL, NULL);  
  72.               
  73.             printf("receive Message: %s\n", recv_buffer);  
  74.         }  
  75.     }  
  76.       
  77.     return 0;  
  78. }  
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/158815
推荐阅读
相关标签
  

闽ICP备14008679号