Linux下C语言使用socket进行线程间通信

 2024-02-01 04:03:40  阅读 0

起源于Unix,Unix/Linux的基本理念之一是“一切皆文件”,可以使用“打开->读/写写/读->关闭”模式进行操作。 它是这种模式的一种实现,即一个特殊的文件,一些函数对其进行操作(读/写IO、打开、关闭)。

说白了,它是应用层和TCP/IP协议族之间进行通信的中间软件抽象层。 它是一组接口。 在设计模式上,实际上是一种门面模式,将复杂的TCP/IP协议族隐藏在接口的背后。 对于用户来说,一组简单的接口就足够了,允许组织数据以符合指定的协议。

注意:实际上,不存在层的概念。 它只是设计模式的一种应用,使编程变得更容易。 它是一个软件抽象层。 在网络编程中,我们使用了很多实现。

除了网络上不同主机之间的通信之外,套接字还可以用于实现同一主机上不同进程之间的通信,并且所建立的通信是双向通信。 进程通信和网络通信使用统一的,但地址结构和一些参数不同。

其主要流程如下:

1. 创建

创建,类型为 or,用于进程通信:

调用函数(),其原型如下:

int(int,int类型,int);

范围:

:指定协议族。 对于本地套接字,该值必须设置为枚举值;

type:指定套接字类型,可以设置为(流套接字)或(数据报套接字)

:指定特定协议,应设置为0

返回值是生成的套接字描述符。

对于本地来说,()是一个有序的、可靠的双向字节流,相当于在本地进程之间建立了一条数据通道; ()相当于单纯的发送消息,在进程通信过程中,理论上可能会出现信息丢失、复制、乱序到达的情况。 不过,由于是本地通信,不经过外部网络,所以这些情况发生的概率很小。

2. 设置参数

本地套接字的通信双方都需要有本地地址。 服务器的本地地址需要明确指定。 指定的方法是使用类型的变量

{

; //

字符[]; // 路径名

3. 绑定

绑定使用bind系统调用,其原型如下:

int 绑定(int, const *,);

范围

:服务器套接字描述符

:需要绑定的服务器本地地址

:本地地址的字节长度

4. 监控

服务器端套接字创建并赋予本地地址值(本例中为名称)后,需要监听,等待客户端连接并处理请求,使用系统调用进行监听,并使用系统调用接受客户端连接。 他们的原型如下:

int (int , int );

int (int, *, *);

范围

:代表服务器端描述符;

表示排队连接队列的长度(如果多个客户端同时连接,则需要排队);

当前连接的客户端的本地地址。 该参数是输出参数,是客户端传递过来的关于自身的信息;

指示当前连接的客户端的本地地址的长度(以字节为单位)。 该参数既是输入参数又是输出参数。 实施监测、验收和处理。

5. 连接

客户端需要 call()来连接服务器,其函数原型如下:

int (int, const *, );

范围

:客户端的套接字描述符

:当前客户端的本地地址,是一个类型变量

:表示本地地址的字节长度

5. 数据交互

客户端和服务器都必须就数据进行交互。 一个进程扮演客户端的角色,另一个进程扮演服务器的角色。 两个进程相互发送和接收数据。 这是基于本地套接字的进程通信。

循环读取客户端发送的消息。 当客户端不发送数据时,它会阻塞,直到数据到达。 如果想要多个连接并发处理,就需要创建一个线程,将每个连接交给对应的线程来并发处理。 接收到数据后,进行相应的处理,并将结果返回给客户端。 要发送和接收数据,需要使用 write 和 read 系统调用。 他们的原型是:

int 读取(int, char *, len);

int write(int, char *, len);

下面是一个本地进程间通信的简单例子:

1. 服务器

#include   
#include   
#include   
#include    
   
#define CAN_SERVICE "CAN_SERVICE" 
int main(void)  
{      
    int ret;     
    int len;  
    int accept_fd;
    int socket_fd; 
    static char recv_buf[1024];
    socklen_t clt_addr_len; 
    struct sockaddr_un clt_addr;  
    struct sockaddr_un srv_addr;  
 
    socket_fd=socket(PF_UNIX,SOCK_STREAM,0);  
    if(socket_fd<0)  
    {  
        perror("cannot create communication socket");  
        return 1;  
    }    
          
    // 设置服务器参数  
    srv_addr.sun_family=AF_UNIX;  
    strncpy(srv_addr.sun_path,CAN_SERVICE,sizeof(srv_addr.sun_path)-1);  
    unlink(CAN_SERVICE);  
 
    // 绑定socket地址 
    ret=bind(socket_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));  
    if(ret==-1)  
    {  
        perror("cannot bind server socket");  
        close(socket_fd);  
        unlink(CAN_SERVICE);  
        return 1;  
    }  
 
    // 监听   
    ret=listen(socket_fd,1);  
    if(ret==-1)  
    {  
        perror("cannot listen the client connect request");  
        close(socket_fd);  
        unlink(CAN_SERVICE);  
        return 1;  
    }  
 
    // 接受connect请求 
    len=sizeof(clt_addr);  
    accept_fd=accept(socket_fd,(struct sockaddr*)&clt_addr,&len);  
    if(accept_fd<0)  
    {  
        perror("cannot accept client connect request");  
        close(socket_fd);  
        unlink(CAN_SERVICE);  
        return 1;  
    }  
 
    // 读取和写入  
    memset(recv_buf,0,1024);  
    int num=read(accept_fd,recv_buf,sizeof(recv_buf));  
    printf("Message from client (%d)) :%s\n",num,recv_buf);    
         
    // 关闭socket
    close(accept_fd);  
    close(socket_fd);  
    unlink(CAN_SERVICE);  
    return 0;  
}  

2. 客户

#include   
#include   
#include   
#include   
 
#define CAN_SERVICE "CAN_SERVICE" 
int main(void)  
{ 
    int ret;  
    int socket_fd;   
    char snd_buf[1024];   
    static struct sockaddr_un srv_addr;  
 
// 创建socket 
    socket_fd=socket(PF_UNIX,SOCK_STREAM,0);  
    if(socket_fd<0)  
    {  
        perror("cannot create communication socket");  
        return 1;  
    }     
    srv_addr.sun_family=AF_UNIX;  
    strcpy(srv_addr.sun_path,CAN_SERVICE);  
 
// 连接到服务器  
    ret=connect(socket_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));  
    if(ret==-1)  
    {  
        perror("cannot connect to the server");  
        close(socket_fd);  
        return 1;  
    }  
    memset(snd_buf,0,1024);  
    strcpy(snd_buf,"message from client");  
 
// 读取和写入    
    write(socket_fd,snd_buf,sizeof(snd_buf));  
    close(socket_fd);  
    return 0;  
}

与本地套接字对应的是网络套接字,可以用来在网络上传输数据。 也就是说,它可以实现不同机器上的进程通信过程。 在TCP/IP协议中,IP地址的第一个字节是127,表示本地,因此可以使用IP地址为127.xxx的网络套接字来实现本地套接字通信。

标签: 通信 进程 字节

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码