Linux进程间的通信之命名socket

目录

 

命名socket

Unix域socket与TCP/IP网络socket之间的区别:

 socket的两种基本方式

编程示例

server头文件

server源文件

client源文件​​​​​​​

运行结果


​​​​​​​

 

目录

 

命名socket

Unix域socket与TCP/IP网络socket之间的区别:

 socket的两种基本方式

编程示例

server头文件

server源文件

client源文件


​​​​​​​

  • 命名socket

使用socket除了可以实现网络间不同主机间的通信外,还可以实现同一主机的不同进程间的通信,且建立的通信是双向的通 信,这种方式就是命名socket(Named Socket)又叫Unix域socket(Unix Domain Socket)。Unix域协议并不是一个实际的 协议族,而是在单个主机上执行客户/服务通信的一种方式,也是进程间通信(IPC)的一种方式。UNIX域数据报服务是可靠 的,不会丢失消息,也不会传递出错。它也提供了两类套接字:字节流套接字(有点像TCP)和数据报套接字(有点像UDP)。
命名socket与普通的TCP/IP网络 socket相比具有以下特点:

  1. UNIX域套接字域传统套接字的区别是用路径名表示协议族的描述,ls -l看到的该文件类型为 s。

  2. UNIX域套接字域TCP套接字相比,在同一台主机的传输速度前者是后者的两倍。UNIX域套接字仅仅复制数据,并不执行 协议处理,不需要添加或删除网络报头,无需计算校验和,不产生顺序号,也不需要发送确认报文 。

  3.  UNIX域套接字可以在同一台主机上各进程之间传递文件描述符。

  • Unix域socket与TCP/IP网络socket之间的区别:

 命名socket与TCP/IP网络socket通信使用的是同一套接口,只是地址结构与某些参数不同:TCP/IP网络socket通过IP地址和 端口号来标识,而UNIX域协议中使用普通文件系统路径名标识。所以命名socket和普通socket只是在创建socket和绑定服务器 标识的时候与网络socket有区别,具体如下:

#include <sys/types.h>          
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
/*
创建一个socket,可以是TCP/IP网络socket,也是命名socket,具体由domain参数决定。该函数的返回值为生成的套接字描述符。
*/


参数说明:

domain:

指定协议族:对于命名socket/Unix域socket,其值须被置为 AF_UNIX或AF_LOCAL;如果是网络socket则其值应该 为 AF_INET; 参数type指定套接字类型,它可以被设置为 SOCK_STREAM(流式套接字)或 SOCK_DGRAM(数据报式套接字)。

protocol:

默认设置为 0。

SOCK_STREAM :

式本地套接字的通信双方均需要具有本地地址,其中服务器端的本地地址需要明确指定,指定方法是使用 struct sockaddr_un 类型的变量。

struct sockaddr_un {  
      sa_family_t     sun_family;         /* AF_UNIX */ 
      char    sun_path[UNIX_PATH_MAX];   /* 路径名 */

};

 

  •  socket的两种基本方式

  1. 一种是普通的命名,socket会根据此命名创建一个同名的socket文 件,客户端连接的时候通过读取该socket文件连接到socket服务端。这种方式的弊端是服务端必须对socket文件的路径具备写权 限,客户端必须知道socket文件路径,且必须对该路径有读权限。

  2. 另外一种命名方式是抽象命名空间,这种方式不需要创建 socket文件,只需要命名一个全局名字,即可让客户端根据此名字进行连接。后者的实现过程与前者的差别是,后者在对地址结 构成员sun_path数组赋值的时候,必须把第一个字节置0,即sun_path[0] = 0。这里第一种方式比较常见,下面的例程中我们 就使用了该方法。

  • 编程示例

  • server头文件


#ifndef __SOCKET_SERVER_H
#define __SOCKET_SERVER_H 
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include<stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/un.h>

#define BUF_SIZE  512
int   socket_start(int domain, int type, int protocol,char* path , char* msg);
int   rdwr_init(int clinefd,char *buf, char *msg);
int   get_opt(int argc, char * const argv[],const char *optstring);
#endif 
  • server源文件

#include "socket_server.h"

void print_usage(char *prograname)
{
    printf("%s usage : \n", prograname);
    printf("-p(--parh): specify sever will go to run with path.\n");
    printf("-m(--msg): specify sever write msg to client.\n");
    printf("-d(--daemon): specify sever will go to run with daemon.\n");
    printf("-h(--help): print this help information.\n");

    return  ;

}
int main(int argc, char *argv[])
{
    get_opt(argc,argv,"p:dm:h");

    return 0;
}

int get_opt(int argc, char * const argv[],const char *optstring)
{
    char*    path;
    int            ch;
    char*    msg = NULL;


    struct option        opts[] = {
        {"path", required_argument, NULL, 'p'},
        {"write_msg", required_argument, NULL, 'm'},
        {"daemon", no_argument, NULL, 'd'},
        {"help", no_argument, NULL, 'h'},
        {NULL, 0, NULL, 0}

    };

    while((ch=getopt_long(argc, argv, "p:m:dh", opts, NULL)) != -1 )
    {
        switch(ch)
        {
            case 'p':
                path=optarg;
                break;
            case 'm':
                msg = optarg;
                break;
            case 'd':
                daemon(0,0);
                break;
            case 'h':
                print_usage(argv[0]);
                return 0;
        }
    }

    if( !path||!msg)
    {
        print_usage(argv[0]);

        return 0;
    }

    if ((socket_start(AF_UNIX, SOCK_STREAM,0, path, msg))< 0)
    {
        printf("socket_start error:%s\n", strerror(errno));
        exit(0);
    }
}
int socket_start(int domain, int type, int protocol, char* path, char *msg)
{
    int                   lisfd = 0;
    int                   clifd = 0;
    int                   on = 1;
    int                   rv = 0;
    char                  buf[BUF_SIZE];
    struct sockaddr_un    serv_addr;
    struct sockaddr_un    cli_addr;
    socklen_t             len = sizeof(serv_addr);

    if ((lisfd = socket(domain,type, protocol))< 0)
    { 
        printf("Socket error:%s\a\n", strerror(errno));
        return -1;
    }

    printf("socket[%d] successfuly!\n", lisfd);

    if ( !access(path, F_OK))
    {
        unlink(path);
    }

    setsockopt(lisfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sun_family = AF_UNIX;
    strncpy(serv_addr.sun_path, path, sizeof(serv_addr.sun_path) - 1);

    if ((rv = bind(lisfd, (struct sockaddr *)&serv_addr, len)) < 0)
    {
        printf("Bind error %s\n", strerror(errno));
        goto EXIT;
    }

    if ((rv = listen(lisfd, 13)) < 0)
    {
        printf("Listen error:%s\n", strerror(errno));
        goto EXIT;
    }

    printf("Waiting clinet to connect.....\n");
    while(1)
    {
        if ((clifd = accept(lisfd, (struct sockaddr *)&cli_addr, &len))< 0)
        {
            printf("Accept error:%s\n", strerror(errno));
            goto EXIT;
        }


        if ((rv = rdwr_init(clifd, buf, msg)) < 0 )
        {
            printf("Write or read form client error:%s\n", strerror(errno));
            goto EXIT;
        }
    }

    return clifd;
EXIT:
    unlink(path);
    close(lisfd );
    close(clifd );
    return -1;
}

int  rdwr_init(int clinefd,char *buf, char * msg)
{
    int                   rv = 0;
    memset(buf,0,  BUF_SIZE);
    while(1)
    {
        if ((rv = read(clinefd, buf, BUF_SIZE)) < 0)
        {
            printf("Read by socket[%d] error:%s\n", clinefd, strerror(errno));
            goto STOP;
        }
        else if (0 == rv)
        {
            printf("The connect get disconneceted.\n");
            goto STOP;
        }
        else if (rv > 0)
        {
              printf("Read %d bytes data from client, there are :%s\n", rv, buf);
        }

        if ((rv =write(clinefd, msg, strlen(msg))) < 0)
        {
            printf("write to cilent by socket[%d] error:%s \n",clinefd, strerror(errno));
            goto STOP;
        }
        printf("Write[%s] to clinet successfuly.\n", msg);



    }
STOP:
    printf("The socket[%d] will eixt!\n", clinefd);
    exit(0);
}
  • client源文件​​​​​​​​​​​​​​

#ifndef __SOCKET_CLIENT__
#define __SOCKET_CLIENT__
#include <sys/types.h>      
#include <sys/socket.h>
#include <string.h>
#include<stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/un.h>
#define	MSG_STR  "Hello network word! I'm client!"
#define	BUF_SIZE  1024
#endif
void print_usage(char *paogname)
{
    printf("%s usage : \n", paogname);
    printf("-p(--path): sepcify connect path.\n");
    printf("-m(--message): The message you want to send.\n");
    printf("-h(--help): print this help information.\n");

    return  ;

}
int main (int argc, char **argv)
{

    int                      sockfd;
    int                      rv = -1;
    struct sockaddr_un       servaddr;
    char*                    path    = NULL;
    char*                    message = NULL;
    char                     buf[BUF_SIZE];
    int                      ch;
    int                      temp;
    struct option        opts[] = {
        {"path", required_argument, NULL, 'p'},
        {"message", required_argument, NULL, 'm'},            
        {"help", no_argument, NULL, 'h'},          
        {NULL, 0, NULL, 0}

    };

    while((ch=getopt_long(argc, argv, "p:m:h", opts, NULL)) != -1 )    
    {
        switch(ch)
        {
            case 'p':   
                path=optarg;
                break;
            case 'm':
                message=optarg;
                break;
            case 'h':
                print_usage(argv[0]);
                return 0;
        }           
    }

    if( !path || !message )        
    {
        print_usage(argv[0]);
        return 0;        
    }

    sockfd = socket(AF_UNIX,SOCK_STREAM,0);
    if(sockfd < 0)
    {
        printf("Cearte socket failure :%s\a\n",strerror(errno));
        return -1;
    }
    printf("Create socket[%d] sucessfully.\n",sockfd);


    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sun_family = AF_UNIX;
    strncpy(servaddr.sun_path, path, sizeof(servaddr.sun_path) - 1);

    rv = connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
    if(rv <0)
    {
        printf("connect toserver[%s] failure :%s\n\a",path,strerror(errno));
        return -2;
    }
    printf("connect to server[%s] successfully!\n",path);


    rv = write(sockfd,message,strlen(message));
    if(rv <0)    
    {
        printf("Write to server failure by socket[%d] failure: %s\n",sockfd,strerror(errno));
        return -3;
    }
    else 
        printf("Write[%s] to server by socket[%d] successfuly!\n", message, sockfd);

    memset(buf,0,sizeof(buf));
    rv = read(sockfd,buf,BUF_SIZE);
    if(rv < 0)
    {
        printf("Read to server socket[%d] failure: %s\n",sockfd,strerror(errno));
        return -4;
    }
    else if(rv == 0)
    {

        printf("socket[%d] get disconnected\n",sockfd);
        return -4;
    }
    else if(rv >0)
    {
        printf("Read %d bytes data form Server: %s\n",rv,buf);
    }
    close(sockfd);
    unlink(path);

    return 0; 
}
  • 运行结果

  1. ​​​​​​​服务器端
  2. 客户端
发布了47 篇原创文章 · 获赞 37 · 访问量 3687

猜你喜欢

转载自blog.csdn.net/qq_44045338/article/details/104999043