进程笔记2:进程之间的通信(UNIX域套接字socket)

来源:互联网 发布:心神战机 知乎 编辑:程序博客网 时间:2024/05/20 02:26

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

struct sockaddr{   sa_family_t sa_family; /* address family*/   char        sa_data[]; /* variable-length address*/   ...};



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

struct sockaddr{   sa_family_t sa_family;   /* address family*/   char        sa_data[14]; /* variable-length address*/};



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


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


创建套接字的函数如下

#include <sys/socket.h>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将其合为了一部分

 /*domain_socket.h@Author: duanjigang @2006-4-11@Desp: declaratin of methods used for unix-domain-socket communication */#ifndef _H_#define _H_#include <stdio.h>#include <unistd.h>#include <sys/un.h>#include <sys/socket.h>#define MSG_SIZE 1024int init_send_socket(struct sockaddr_un * addr,char * path){        int sockfd,len;        sockfd=socket(AF_UNIX,SOCK_DGRAM,0);        if(sockfd<0)        {                exit(1);        }        bzero(addr,sizeof(struct sockaddr_un));        addr->sun_family=AF_UNIX;        strcpy(addr->sun_path,path);        return sockfd;}int init_recv_socket(char * path){        int sockfd,len;         struct sockaddr_un addr;         sockfd=socket(AF_UNIX,SOCK_DGRAM,0);         if(sockfd<0)         {            return -1;        }         bzero(&addr,sizeof(struct sockaddr_un));         addr.sun_family = AF_UNIX;         strcpy(addr.sun_path, path);        unlink(path);        len = strlen(addr.sun_path) + sizeof(addr.sun_family);        if(bind(sockfd,(struct sockaddr *)&addr,len)<0)          {           return -1;         }         return sockfd;}int receive_from_socket(int sockfd, char msg[]){      int n;       memset(msg, 0, MSG_SIZE);      n=recvfrom(sockfd, msg, MSG_SIZE, 0, NULL, NULL);       if(n<=0)      {       return -1;      }      msg[n]=0;      return n;}int send_to_socket(int sockfd, char msg[], const struct sockaddr_un * addr){        int len;         len = strlen(addr->sun_path)+sizeof(addr->sun_family);        sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)addr,len);         return 1;}#endif



/*main.c@Author: duanjigang @ 2006-4-11@Desp: Two processes communicate with unix domain socket*/#include "domain_socket.h"#define PATH "/home/useless"/*进程间通过域进行通讯-举例:父子进程,一个发送,一个接收*/int main(void){  int pid;  /*  子进程用于发送消息  */  if((pid = fork()) == 0)  {    int fd, counter = 0;    char send_buffer[MSG_SIZE];    struct sockaddr_un addr;    if( (fd = init_send_socket(&addr, PATH)) > 0)    while(1)    {       memset(send_buffer, 0 , MSG_SIZE);       /*           防止计数器越界,所以做一个复位判断           */       sprintf(send_buffer,"message for %d times",counter++ >= 10000 ? 1 : counter);       send_to_socket(fd, send_buffer, &addr);       printf("Sender: %s\n", send_buffer);       sleep(1);    }  }/*   父进程用于接收消息  */  else  {      int fd;      char recv_buffer[MSG_SIZE];      if( (fd = init_recv_socket(PATH))> 0)      while(1)      {       memset(recv_buffer, 0, MSG_SIZE);       if(receive_from_socket(fd, recv_buffer))       {            printf("Receiver: %s\n", recv_buffer);       }      }  }} 


运行结果示例:

Sender: message for 1 timesSender: message for 2 timesReceiver: message for 2 timesSender: message for 3 timesReceiver: message for 3 timesSender: message for 4 timesReceiver: message for 4 timesSender: message for 5 timesReceiver: message for 5 times




socket_unix.c

//利用UNIX域套接字通信#include <stdio.h>#include <unistd.h>#include <sys/un.h>#include <sys/socket.h>#define MSG_MAX_SIZE 1024#define PATH "a.socket"//套接字文件int main(){    int len;    int socket_fd;    struct sockaddr_un addr;    bzero(&addr, sizeof(struct sockaddr_un));    addr.sun_family = AF_UNIX;    strcpy(addr.sun_path, PATH);     len = strlen(addr.sun_path)+sizeof(addr.sun_family);        if(!fork())//子进程内部代码    {        int counter = 0;        char send_buffer[MSG_MAX_SIZE];        //init send socket        socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);         if(socket_fd<0)        {            printf("client socket error!");            return 0;        }                while(1) //循环发送数据消息        {            memset(send_buffer, 0, MSG_MAX_SIZE);            sprintf(send_buffer, "message for %d times", counter++);                        //将数据信息发送到addr指定的套接字文件之中,所以这样进程之间就可以进行通信            sendto(socket_fd, send_buffer, strlen(send_buffer), 0, (struct sockaddr*)&addr, len);            printf("sender:%s\n", send_buffer);            sleep(1);        }    }    else    {        char recv_buffer[MSG_MAX_SIZE];        //init recv socket        socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);        if(socket_fd<0)        {            printf("server socket error!");            return 0;        }                unlink(PATH);//防止要创建的socket文件已存在        if(bind(socket_fd, (struct sockaddr *)&addr, len)<0)//只有bind以后才会在硬盘创建套接字PATH        {            printf("bind error");            return 0;        }        while(1)//循环接收数据        {            memset(recv_buffer, 0, MSG_MAX_SIZE);            //receive from socket从指定socket中读取数据,这里socket已经绑定了指定的PATH的文件            recvfrom(socket_fd, recv_buffer, MSG_MAX_SIZE, 0, NULL, NULL);                        printf("receive Message: %s\n", recv_buffer);        }    }        return 0;}


原创粉丝点击