socket本地多进程通信基本使用方法和示例

2023-05-16

目录

前言:

socket是什么

 socket基本原理框图

socket基本函数

1 socket() 函数

2 bind()函数

3 connect()函数

4 listen() 函数

5 accept() 函数

6 read() write() send() recv()函数

7 close()函数

8 字节序转换(hton)

示例代码


前言:

进程间通信(IPC,Interprocess communication)是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。这使得一个程序能够在同一时间里处理许多用户的要求。因为即使只有一个用户发出要求,也可能导致一个操作系统中多个进程的运行,进程之间必须互相通话。IPC接口就提供了这种可能性。每个IPC方法均有它自己的优点和局限性,一般,对于单个程序而言使用所有的IPC方法是不常见的。

进程间通信的8种方法:

1、无名管道通信

无名管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

2、高级管道通信

高级管道(popen):将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。

3、有名管道通信

有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

4、消息队列通信

消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

5、信号量通信

信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

6、信号

信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

7、共享内存通信

共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。

8、套接字通信

套接字( socket ) : 套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

socket是什么

你也许听很多高手说过,UNIX/Linux 中的一切都是文件!那个家伙说的没错。
为了表示和区分已经打开的文件,UNIX/Linux 会给每个文件分配一个 ID,这个 ID 就是一个整数,被称为文件描述符(File Descriptor)。例如:

  • 通常用 0 来表示标准输入文件(stdin),它对应的硬件设备就是键盘;
  • 通常用 1 来表示标准输出文件(stdout),它对应的硬件设备就是显示器。

UNIX/Linux 程序在执行任何形式的 I/O 操作时,都是在读取或者写入一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数,它的背后可能是一个硬盘上的普通文件、FIFO、管道、终端、键盘、显示器,甚至是一个网络连接。

请注意,网络连接也是一个文件,它也有文件描述符!你必须理解这句话。

我们可以通过 socket() 函数来创建一个网络连接,或者说打开一个网络文件,socket() 的返回值就是文件描述符。有了文件描述符,我们就可以使用普通的文件操作函数来传输数据了,例如:

  • 用 read() 读取从远程计算机传来的数据;
  • 用 write() 向远程计算机写入数据。


你看,只要用 socket() 创建了连接,剩下的就是文件操作了,socket通信原来就是如此简单!


 
socket基本原理框图

1.服务端首先初始化Socket(),然后和接口进行绑定bind()和监听listen(),然后调用accept()进行阻塞。
2.客户端初始化socket(),然后调用connect()与服务端进行连接,然后客户端负责发送请求,服务端接收并且处理请求。write(),read().在 UNIX/Linux 系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。

socket基本函数

1 socket() 函数

#include <sys/types.h>
#include <sys/socket.h>
int socket (int af, int type, int protocal );

1) af 为地址族(Address Family),也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6。AF 是“Address Family”的简写,INET是“Inetnet”的简写。AF_INET 表示 IPv4 地址,例如 127.0.0.1;AF_INET6 表示 IPv6 地址,例如 1030::C9B4:FF12:48AA:1A2B。

大家需要记住127.0.0.1,它是一个特殊IP地址,表示本机地址。

2) type 为数据传输方式/套接字类型,常用的有 SOCK_STREAM(流格式套接字/面向连接的套接字) 和 SOCK_DGRAM(数据报套接字/无连接的套接字)

3) protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议。

2 bind()函数

socket()函数用来创建套接字,确定套接字的各种属性,然后服务器端要用 bind() 函数将套接字与特定的 IP 地址和端口绑定起来,只有这样,流经该 IP 地址和端口的数据才能交给套接字处理。类似地,客户端也要用 connect() 函数建立连接。

#include <sys/types.h>
#include <sys/socket.h>
int bind (int sockfd, const struct sockaddr* my_addr, socklen_t addlen );
//前边的专用地址的指针强制转换成 struct sockaddr* 就行

1)sock 为 socket 文件描述符,

2)addr 为 sockaddr 结构体变量的指针,

3)addrlen 为 addr 变量的大小,可由 sizeof() 计算得出。

下面的代码,将创建的套接字与IP地址 127.0.0.1、端口 1234 绑定:

    //创建套接字
    int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    //创建sockaddr_in结构体变量
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
    serv_addr.sin_family = AF_INET;  //使用IPv4地址
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址
    serv_addr.sin_port = htons(1234);  //端口
    //将套接字和IP、端口绑定
    bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

这里我们使用 sockaddr_in 结构体,然后再强制转换为 sockaddr 类型,后边会讲解为什么这样做。

sockaddr_in 结构体

接下来不妨先看一下 sockaddr_in 结构体,它的成员变量如下:

    struct sockaddr_in{
        sa_family_t     sin_family;   //地址族(Address Family),也就是地址类型
        uint16_t        sin_port;     //16位的端口号
        struct in_addr  sin_addr;     //32位IP地址
        char            sin_zero[8];  //不使用,一般用0填充
    };

1) sin_family 和 socket() 的第一个参数的含义相同,取值也要保持一致。

2) sin_prot 为端口号。uint16_t 的长度为两个字节,理论上端口号的取值范围为 0~65536,但 0~1023 的端口一般由系统分配给特定的服务程序,例如 Web 服务的端口号为 80,FTP 服务的端口号为 21,所以我们的程序要尽量在 1024~65536 之间分配端口号。

端口号需要用 htons() 函数转换,后面会讲解为什么。

3) sin_addr 是 struct in_addr 结构体类型的变量,下面会详细讲解。

4) sin_zero[8] 是多余的8个字节,没有用,一般使用 memset() 函数填充为 0。上面的代码中,先用 memset() 将结构体的全部字节填充为 0,再给前3个成员赋值,剩下的 sin_zero 自然就是 0 了。

in_addr 结构体

sockaddr_in 的第3个成员是 in_addr 类型的结构体,该结构体只包含一个成员,如下所示:

    struct in_addr{
        in_addr_t  s_addr;  //32位的IP地址
    };

in_addr_t 在头文件 <netinet/in.h> 中定义,等价于 unsigned long,长度为4个字节。也就是说,s_addr 是一个整数,而IP地址是一个字符串,所以需要 inet_addr() 函数进行转换,例如:

    unsigned long ip = inet_addr("127.0.0.1");
    printf("%ld\n", ip);

运行结果:
16777343

为什么要搞这么复杂,结构体中嵌套结构体,而不用 sockaddr_in 的一个成员变量来指明IP地址呢?socket() 函数的第一个参数已经指明了地址类型,为什么在 sockaddr_in 结构体中还要再说明一次呢,这不是啰嗦吗?

这些繁琐的细节确实给初学者带来了一定的障碍,我想,这或许是历史原因吧,后面的接口总要兼容前面的代码。各位读者一定要有耐心,暂时不理解没有关系,根据教程中的代码“照猫画虎”即可,时间久了自然会接受。

为什么使用 sockaddr_in 而不使用 sockaddr

bind() 第二个参数的类型为 sockaddr,而代码中却使用 sockaddr_in,然后再强制转换为 sockaddr,这是为什么呢?

sockaddr 结构体的定义如下:

    struct sockaddr{
        sa_family_t  sin_family;   //地址族(Address Family),也就是地址类型
        char         sa_data[14];  //IP地址和端口号
    };

下图是 sockaddr 与 sockaddr_in 的对比(括号中的数字表示所占用的字节数):

 sockaddr 和 sockaddr_in 的长度相同,都是16字节,只是将IP地址和端口号合并到一起,用一个成员 sa_data 表示。要想给 sa_data 赋值,必须同时指明IP地址和端口号,例如”127.0.0.1:80“,遗憾的是,没有相关函数将这个字符串转换成需要的形式,也就很难给 sockaddr 类型的变量赋值,所以使用 sockaddr_in 来代替。这两个结构体的长度相同,强制转换类型时不会丢失字节,也没有多余的字节。

可以认为,sockaddr 是一种通用的结构体,可以用来保存多种类型的IP地址和端口号,而 sockaddr_in 是专门用来保存 IPv4 地址的结构体。另外还有 sockaddr_in6,用来保存 IPv6 地址,它的定义如下:

    struct sockaddr_in6 { 
        sa_family_t sin6_family;  //(2)地址类型,取值为AF_INET6
        in_port_t sin6_port;  //(2)16位端口号
        uint32_t sin6_flowinfo;  //(4)IPv6流信息
        struct in6_addr sin6_addr;  //(4)具体的IPv6地址
        uint32_t sin6_scope_id;  //(4)接口范围ID
    };

正是由于通用结构体 sockaddr 使用不便,才针对不同的地址类型定义了不同的结构体。

3 connect()函数

#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen ); //成功返回服务端的文件描述符

各个参数的说明和 bind() 相同,不再赘述。

4 listen() 函数

#include <sys/socket.h>
int listen( int sockfd, int backlog ); //backlog是指完全连接(ESTABLISHED)的客户端的上限

对于服务器端程序,使用 bind() 绑定套接字后,还需要使用 listen() 函数让套接字进入被动监听状态,再调用 accept() 函数,就可以随时响应客户端的请求了。

sock 为需要进入监听状态的套接字,backlog 为请求队列的最大长度。

所谓被动监听,是指当没有客户端请求时,套接字处于“睡眠”状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求。

请求队列

当套接字正在处理客户端请求时,如果有新的请求进来,套接字是没法处理的,只能把它放进缓冲区,待当前请求处理完毕后,再从缓冲区中读取出来处理。如果不断有新的请求进来,它们就按照先后顺序在缓冲区中排队,直到缓冲区满。这个缓冲区,就称为请求队列(Request Queue)。

缓冲区的长度(能存放多少个客户端请求)可以通过 listen() 函数的 backlog 参数指定,但究竟为多少并没有什么标准,可以根据你的需求来定,并发量小的话可以是10或者20。

如果将 backlog 的值设置为 SOMAXCONN,就由系统来决定请求队列长度,这个值一般比较大,可能是几百,或者更多。

当请求队列满时,就不再接收新的请求,对于 Linux,客户端会收到 ECONNREFUSED 错误,对于 Windows,客户端会收到 WSAECONNREFUSED 错误。

注意:listen() 只是让套接字处于监听状态,并没有接收请求。接收请求需要使用 accept() 函数

5 accept() 函数

#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen ); //成功返回客户端的文件描述符

当套接字处于监听状态时,可以通过 accept() 函数来接收客户端请求

它的参数与 listen() 和 connect() 是相同的:sock 为服务器端套接字,addr 为 sockaddr_in 结构体变量,addrlen 为参数 addr 的长度,可由 sizeof() 求得。
accept() 返回一个新的套接字来和客户端通信,addr 保存了客户端的IP地址和端口号,而 sock 是服务器端的套接字,大家注意区分。后面和客户端通信时,要使用这个新生成的套接字,而不是原来服务器端的套接字。
最后需要说明的是:listen() 只是让套接字进入监听状态,并没有真正接收客户端请求,listen() 后面的代码会继续执行,直到遇到 accept()。accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来。

6 read() write() send() recv()函数

write() read() 通用读写
ssize_t write(int fd, const void *buf, size_t nbytes);
ssize_t read(int fd, void *buf, size_t nbytes);

前面我们说过,两台计算机之间的通信相当于两个套接字之间的通信,在服务器端用 write() 向套接字写入数据,客户端就能收到,然后再使用 read() 从套接字中读取出来,就完成了一次通信。

除此之外还有其他方法进行读写套接字如下:


TCP数据读写
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags );
ssize_t send(int sockfd, void *buf, size_t len, int flags );

UDP读写
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addlen);
ssize_t sendto(int sockfd, void *buf, size_t len, int flags, struct sockaddr *dest_addr, socklen_t *addlen);

socket通用读写
#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags );
ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags );
struct msghdr
{
    void *msg_name;			//socket地址
    socklen_t msg_namelen	//socket地址长度
    struct iovec *msg_iov;	//分散的内存块数组
    int msg_iovlen;			//内存块数量
    void *msg_control;		//指向辅助数据的起始位置
    socklen_t msg_controllen;//辅助数据长度
    int msg_flags;			//复制函数中的flags
};
struct iovec
{
  	void *iov_base;	//内存起始地址
    size_t iov_len;	//这块内存长度
};

7 close()函数

#include <unistd.h>
int close(int fd); //通用文件描述符关闭,将fd的引用计数减一

#include <sys/socket.h>
int shutdown(int sockfd, int howto ); //网络专用,howto取值SHUT_RD, SHUT_WR, SHUT_RDWR。

8 字节序转换(hton)

#include <netinet/in.h>
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);
unsigned long int ntohl(unsigned long int netlong);
unsigned short int ntohs(unsigned short int netshort);

htons是将整型变量从主机字节顺序转变成网络字节顺序, 就是整数在地址空间存储方式变为高位字节存放在内存的低地址处。
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释,网络字节顺序采用big-endian排序方式。
htons的功能:将一个无符号短整型的主机数值转换为网络字节顺序,即大尾顺序(big-endian)

htonl,其实是host to network, l 的意思是返回类型是long. 将主机数转换成无符号长整型的网络字节顺序。本函数将一个32位数从主机字节顺序转换成网络字节顺序。

示例代码

本示例是本地多进程间进行通信,完成进程1和进程2分别和service进程建立socket,进而使本地进程1和进程2进行通信

client1 代码

/*************************************************************************
	> file Name: client.c
	> author: C G
	> mail: - 
	> created Time: 2023年03月01日 星期三 18时19分46秒
	> version: 1.0
 ************************************************************************/
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/time.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/time.h>
#include<string.h>
#include"../common.h"


int init(void)
{
	int len = 0;
	int clientSockfd = 0;
	int clientLen= 0;
	int result = 0;
	struct sockaddr_in clientAddress;
	struct sockaddr_in serverAddress;

	clientSockfd = socket(AF_INET, SOCK_STREAM, 0);

	memset(&serverAddress, 0x00, sizeof(serverAddress));
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_addr.s_addr = inet_addr(SERVICE_STRING_IP);
	serverAddress.sin_port = htons(SERVICE_PORT);
	len = sizeof(serverAddress);

	memset(&clientAddress, 0x00, sizeof(clientAddress));
	clientAddress.sin_family = AF_INET;
	clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
	clientAddress.sin_port = htons(BT_PORT_ID);
	clientLen = sizeof(clientAddress);

	bind(clientSockfd, (struct sockaddr*)&clientAddress, clientLen);

	result = connect(clientSockfd, (struct sockaddr *)&serverAddress, len);

	if(result == -1)
	{
		printf("connect result is error\n");
		exit(1);
	}

	return clientSockfd;
}


int main()
{
	int clientSockfd = 0;
	struct Data myData;

	struct timeval start;
	struct timeval end;

	clientSockfd = init();

	printf("i am is BT\n");

	memset(&myData, 0x00, sizeof(myData));
	myData.src = BT_PORT_ID;
	myData.der = HMI_PORT_ID;
	myData.evt = 1;

	write(clientSockfd, &myData, sizeof(myData));

	gettimeofday(&start,NULL);
	printf("BT write time is %ld.%06ld\n",start.tv_sec, start.tv_usec);
	printf("BT write src = %d , der = %d , evt = %d \n",myData.src, myData.der, myData.evt);


	memset(&myData, 0x00, sizeof(myData));
	read(clientSockfd, &myData, sizeof(myData));

	gettimeofday(&end,NULL);
	printf("BT read time is %ld.%06ld\n",end.tv_sec, end.tv_usec);
	printf("BT read src = %d , der = %d , evt = %d \n",myData.src, myData.der, myData.evt);


	close(clientSockfd);

	return 0;
}

client 2 代码

/*************************************************************************
	> file Name: client.c
	> author: C G
	> mail: - 
	> created Time: 2023年03月01日 星期三 18时19分46秒
	> version: 1.0
 ************************************************************************/
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/time.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/time.h>
#include<string.h>
#include"../common.h"


int init(void)
{
	int len = 0;
	int clientSockfd = 0;
	int clientLen= 0;
	int result = 0;
	struct sockaddr_in clientAddress;
	struct sockaddr_in serverAddress;

	clientSockfd = socket(AF_INET, SOCK_STREAM, 0);

	memset(&serverAddress, 0x00, sizeof(serverAddress));
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_addr.s_addr = inet_addr(SERVICE_STRING_IP);
	serverAddress.sin_port = htons(SERVICE_PORT);
	len = sizeof(serverAddress);

	memset(&clientAddress, 0x00, sizeof(clientAddress));
	clientAddress.sin_family = AF_INET;
	clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
	clientAddress.sin_port = htons(HMI_PORT_ID);
	clientLen = sizeof(clientAddress);

	bind(clientSockfd, (struct sockaddr*)&clientAddress, clientLen);

	result = connect(clientSockfd, (struct sockaddr *)&serverAddress, len);

	if(result == -1)
	{
		printf("connect result is error\n");
		exit(1);
	}

	return clientSockfd;
}


int main()
{
	int clientSockfd = 0;
	struct Data myData;

	struct timeval start;
	struct timeval end;

	clientSockfd = init();
	printf("i am HMI\n");

	memset(&myData, 0x00, sizeof(myData));

	read(clientSockfd, &myData, sizeof(myData));
	gettimeofday(&end,NULL);
	printf("HMI read time is %ld.%06ld\n",end.tv_sec, end.tv_usec);
	printf("HMI read src = %d , der = %d , evt = %d \n",myData.src, myData.der, myData.evt);

	memset(&myData, 0x00, sizeof(myData));
	myData.src = HMI_PORT_ID;
	myData.der = BT_PORT_ID;
	myData.evt = 2;

	write(clientSockfd, &myData, sizeof(myData));

	gettimeofday(&start,NULL);
	printf("HMI write time is %ld.%06ld\n",start.tv_sec, start.tv_usec);
	printf("HMI write src = %d , der = %d , evt = %d \n",myData.src, myData.der, myData.evt);

	close(clientSockfd);

	return 0;

}

service 代码


/*************************************************************************
	> file Name: service.c
	> author: C G
	> mail: - 
	> created Time: 2023年03月01日 星期三 18时15分49秒
	> version: 1.0
 ************************************************************************/

extern "C"
{
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<sys/time.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>

#include"../common.h"
}


#include<map>

int main()
{
	std::map<int, int> myMap;

	int server_sockfd,client_sockfd;
	unsigned int server_len, client_len;
	struct sockaddr_in server_address;
	struct sockaddr_in client_address;
	int result;
	fd_set readfds, testfds;

	struct Data myData;
	memset(&myData, 0x00, sizeof(myData));

	server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
	server_address.sin_family = AF_INET;
	server_address.sin_addr.s_addr = htonl(INADDR_ANY);
	server_address.sin_port = htons(SERVICE_PORT);
	server_len = sizeof(server_address);

	bind(server_sockfd, (struct sockaddr*)&server_address, server_len);
	listen(server_sockfd, LISTEN_MAX);

	FD_ZERO(&readfds);
	FD_SET(server_sockfd,&readfds);

	while(1)
	{
		char ch;
		int fd;
		int nread;
		ssize_t readSize = 0;
		
		FD_ZERO(&testfds);
		testfds = readfds;
		result = select(FD_SETSIZE, &testfds, (fd_set*)0, (fd_set*)0, NULL);
		if(result  < 1)
		{
			printf("is error\n");
			exit(1);
		}

		for(fd = 0; fd < FD_SETSIZE; fd++)
		{
			if(FD_ISSET(fd, &testfds))
			{
				if(fd == server_sockfd)
				{
					client_len = sizeof(client_address);
					client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_address, &client_len);
					FD_SET(client_sockfd, &readfds);
					printf("adding client on fd %d  port %d ID:%s\n", client_sockfd, ntohs(client_address.sin_port), 
							HMI_PORT_ID==ntohs(client_address.sin_port)?"HMI_PORT_ID":BT_PORT_ID==ntohs(client_address.sin_port)?"BT_PORT_ID":"other_port_ID");
					myMap[ntohs(client_address.sin_port)] = client_sockfd;
				}
				else
				{
					readSize = read(fd, &myData, sizeof(myData));

					if(readSize > 0)
					{
						struct timeval start;
						gettimeofday(&start,NULL);
						printf("read time is %ld.%06ld\n",start.tv_sec, start.tv_usec);

						printf("read client on fd %d ID %s,src = %d , der = %d  => %d, evn = %d \n",fd,
								HMI_PORT_ID==myData.der?"HMI_PORT_ID":BT_PORT_ID==ntohs(client_address.sin_port)?"BT_PORT_ID":"other_port_ID",
								myData.src, myData.der, myMap[myData.der],myData.evt);

						write(myMap[myData.der], &myData, sizeof(myData));

						printf("write client on fd %d ID %s,src = %d , der = %d  => %d, evn = %d \n\n",fd,
								HMI_PORT_ID==myData.der?"HMI_PORT_ID":BT_PORT_ID==ntohs(client_address.sin_port)?"BT_PORT_ID":"other_port_ID",
								myData.src, myData.der, myMap[myData.der],myData.evt);
					}
					else
					{
						FD_CLR(fd, &readfds);
						printf("removing client on fd %d\n",fd);
						std::map<int,int>::iterator key = myMap.find(fd);
						if(key != myMap.end())
						{
							myMap.erase(key);
						}
						nread++;
						write(fd, &nread, 1);
					}
				}
			}
		}
	}

	return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

socket本地多进程通信基本使用方法和示例 的相关文章

  • C#基础知识篇:C#网络编程(Socket)使用poll函数判断连接断开问题

    C Socket使用poll函数判断连接断开问题 最近在学习c 的网络编程内容 遇到这样一个问题 在服务器端 如何判断客户端的一个连接是否断开 查找相关资料 得出较好的解决方案是使用socket对象的poll函数 poll函数分析 下面是p
  • 优雅地断开TCP连接

    socket关闭 close 和shutdown 的差异 对于一个tcp连接 在c语言里一般有2种方法可以将其关闭 close sock fd 或者 shutdown sock fd 多数情况下这2个方法的效果没有区别 可以互换使用 除了
  • MFC实现socket网络通信--主机与服务器之间传送数据

    MFC实现socket网络通信 模拟主机与服务器之间传送数据 MFC实现socket网络通信 1 新建MFC应用程序 2 创建服务端窗口界面 3 写服务器代码 4 创建客户端窗口界面 5 客户端代码部分 6 开始调试 7 小结 MFC实现s
  • iOS平台Socket编程实践(一)

    iOS平台Socket编程实践 关于TCP Socket编程基础可以参看我的 我所不知道的TCP Socket编程 系列文章 iOS平台Socket编程主要内容及辅助工具 1 TCP协议编程 2 UDP协议编程 3 WireShark抓包辅
  • Java图书管理系统 -- 基于Socket实现客户端服务端拆分

    图书管理系统小Demo又又又升级了 本图书管理系统已经经历了三个阶段 通过操作数组来实现图书的增删改查方法 用控制台获取用户输入来实现人机交互 通过集合容器存储对象 使用序列化在管理系统开启关闭时 加载 存储数据到本地 使用TCP协议实现客
  • Java NIO介绍(二)————无堵塞io和Selector简单介绍

    无堵塞IO介绍 既然NIO相比于原来的IO在读取速度上其实并没有太大区别 因为NIO出来后 IO的低层已经以NIO为基础重新实现了 那么NIO的优点是什么呢 NIO是一种同步非阻塞的I O模型 也是I O多路复用的基础 而且已经被越来越多地
  • Socket编程之聊天程序 - 模拟Fins/ModBus协议通信过程

    设备控制软件编程涉及到的基本通信方式主要有TCP IP与串口 用到的数据通信协议有Fins与ModBus 更高级别的通信如 net中的Remoting与WCF在进行C S架构软件开发时会采用 本篇文章结合Fins ModBus协议的指令帧结
  • Socket传输文件/传输图片(Windows)

    利用UDP socket 来传输文件与图片 流程图如下 主要流程 1 client端发送command请求 上传数据或者下载数据 选择文件路径 2 server端应答 start代表开始传输 no代表拒绝 3 fopen打开文件进行读取 f
  • IOS 网络初探(一) - NSURLConnection

    在IOS中 除了最基本的socket外 苹果提供了NSURLConnection类来实现网络通信 请求服务器数据 GET方式 请求服务器数据分成异步和同步两种方式 先来看看异步 非阻塞 NSURL url NSURL URLWithStri
  • Java网络编程之带文件名的文件传输(服务器+客户端)

    Java网络编程之带文件名的文件传输 文章总览 作者的话 需求分析 客户端代码 服务器端代码 服务器线程定义 结语 文章总览 作者的话 最近做的某个项目涉及到这方面的内容 因有感写下这篇学习记录 希望能给和我一样正在学习java的朋友们起到
  • Unity使用C#实现简单Scoket连接及服务端与客户端通讯

    简介 网络编程是个很有意思的事情 偶然翻出来很久之前刚开始看Socket的时候写的一个实例 贴出来吧 Unity中实现简单的Socket连接 c 中提供了丰富的API 直接上代码 服务端代码 Thread connectThread 当前服
  • 使用socket判断http请求或http响应的传输结束

    使用socket判断http请求或http响应的传输结束 先把header直到 r n r n整个地收下来 1 传输完毕就关闭connection 即recv收到0个字节 2 有内容 if Transfer Encoding chunked
  • 关于Socket编程中的inet_ntop、inet_pton和inet_ntoa、inet_addr

    VS2013中调试Socket代码时 遇到了点小问题 问题代码为 cpp view plain copy inet ntoa addrClient sin addr 生成错误消息为 plain view plain copy error C
  • 使用Java socket简单模拟HTTP服务器

    1 HTTP server 接收client端的http请求并将同级目录的root 返回 package httpDemo import java io InputStream import java io OutputStream imp
  • /etc/init.d/mysql: No such file or directory 和 ERROR 2002 (HY000): Can't connect to local MySQL server through socket 解决办法

    更改 etc my cnf client password your password port 3306 socket tmp mysql sock Here follows entries for some specific progr
  • Java中的NIO和IO的对比分析

    总的来说 java中的IO和NIO主要有三点区别 IO NIO 面向流 面向缓冲 阻塞IO 非阻塞IO 无 选择器 Selectors 1 面向流与面向缓冲 Java NIO和IO之间第一个最大的区别是 IO是面向流的 NIO是面向缓冲区的
  • TCP/IP编程实现远程文件传输

    TCP IP编程实现远程文件传输 在TCP IP网络结构中 为了保证网络安全 网络人员往往需要在路由器上添加防火墙 禁止非法用户用ftp等安全危害较大的TCP IP协议访问主机 而有时系统维护人员需要用ftp将一些文件从中心机房主机传到前端
  • socket连接超时问题

    一部分 把CSDN与中文yahoo翻了底朝天 也没找到如何设置socket的连接超时的满意方法 问此问题的兄弟已有一大堆 这里偶就讲一下win下如何设置socket的connect超时 设置connect的超时很简单 CSDN上也有人提到过
  • golang之跨语言ipc通信

    1 golang之跨语言ipc通信 文章目录 1 golang之跨语言ipc通信 1 1 unix domain Socket unix域套接字 介绍 1 2 IPC SOCKET通信 1 2 1 函数及地址定义介绍 1 2 2 UNIX
  • Socket编程中的强制关闭与优雅关闭及相关socket选项

    以下描述主要是针对windows平台下的TCP socket而言 首先需要区分一下关闭socket和关闭TCP连接的区别 关闭TCP连接是指TCP协议层的东西 就是两个TCP端之间交换了一些协议包 FIN RST等 具体的交换过程可以看TC

随机推荐

  • UBUNTU系统VS Code报错 “The ‘clang-format‘ command is not available. Please check your clang-format.“

    看网上都是windows的解决方法 xff0c ubuntu解决比较简单 xff1a https github com xaverh vscode clang format provider issues 48 span class tok
  • PCL库中,去除噪声离群点

    参考来源 xff1a https zhuanlan zhihu com p 102748557 首先用最简单的 xff0c 半径距离筛选大部分离群点 96 span class token macro property span class
  • TensorFlow的InvalidArgumentError类

    原文链接 f errors InvalidArgumentError tf errors InvalidArgumentError 类 定义在 xff1a tensorflow python framework errors impl py
  • ADRC学习

    学习ADRC先从提出这个算法的论文 从 PID 技术到 自抗扰控制 技术 开始 https download csdn net download qq 34445388 10309935 调试四轮智能车 xff0c 板球控制系统 xff0c
  • Ubuntu中切换默认python版本

    在ubuntu中切换默认python版本 有时候需要在默认python中使用不通版本的python xff0c 这里对于该操作做一下记录 当前版本 xff08 Ubuntu 18 04 xff09 python3 结果是 Python sp
  • 计算机图形学的一些公式

    说明 本文公式由 数字图像处理 xff08 第三版 xff09 中摘录而得 xff0c 供以后参考 正文 1 二维图像仿射变换矩阵图 2 双线性内插 v x y 61 a x 43 b y 43 c x y 43 d 3 双三次内插 v x
  • 基于opencv的四轴飞行器寻迹系统(一)——linux下opencv的安装

    文章的内容本身是为2017全国大学生电子设计大赛飞行器方向题准备的 xff0c 在七月底的时候寻迹的图像处理方面已经完成的差不多了 xff0c 能实现非常精确的巡线 xff0c 实际测试即使背景不是白布 xff0c 也可以轻松分辨出道路 拟
  • setStyleSheet用法

    https www cnblogs com aheng123 p 5630761 html 使用setStyleSheet来设置图形界面的外观 xff1a QT Style Sheets是一个很有利的工具 xff0c 允许定制窗口的外观 x
  • 裸辞2个月找不到工作,我慌了

    3月初裸辞 xff0c 找了近2个月的工作了 xff0c 至今还没找到 xff0c 感觉心好慌 xff0c 不知道该怎么办了 xff1f 裸辞多久找不到工作 xff0c 心态会崩 xff1f 找不到工作的时候压力很大 xff0c 有人说自信
  • CMakeList 详解

    CMake 构建脚本是一个纯文本文件 xff0c 您必须将其命名为 CMakeLists txt xff0c 并在其中包含 CMake 构建您的 C C 43 43 库时需要使用的命令 如果您的原生源代码文件还没有 CMake 构建脚本 x
  • 【Python源码阅读】PYC 文件剖析

    pyc 文件相信大家见怪不怪 xff0c 大家经常在 pycache 里面见到这些文件 这些文件存储了 python 编译出来的字节码文件 xff0c 还有一些元信息 xff08 例如版本号 xff0c 对应文件的修改时间 xff09 接下
  • 【小米手环7】使用 Zeus + 表盘自定义工具 为小米手环7开发和安装小程序

    有关 Zepp OS Zepp OS 是华米开发的一个 RTOS xff0c 运行在手表 手环等设备上 最新发布的小米手环7 7NFC 搭载的就是由华米研发的 Zepp OS 相比与之前小米手环搭载的 RTOS xff0c Zepp OS
  • 使用memoize解决PEG解析器无法左递归的问题

    本篇文章是个人对 Guido 有关 Packrat PEG 解析器文章的处理左递归部分的理解和总结 左递归 众所周知 xff0c PEG 解析器的一个缺陷就在于无法解析具有左递归的文法 xff0c 而大多数情况下 xff0c CFG 使用左
  • 观测器计算频率与效果对比

    文章目录 速度环内计算 8KHz 速度环内计算 xff0c 加400Hz低通滤波相位延迟 电流环内计算 16KHz 观测器带宽160Hz xff0c 800HzLPF观测器带宽236Hz xff0c 无LPF观测器带宽236Hz xff0c
  • Docker 10张图带你深入理解Docker容器和镜像

    这篇文章希望能够帮助读者深入理解Docker的命令 xff0c 还有容器 xff08 container xff09 和镜像 xff08 image xff09 之间的区别 xff0c 并深入探讨容器和运行中的容器之间的区别 题外话 xff
  • Nginx 多进程模型

    Nginx 整体结构 Nginx运行在企业内网的边缘节点 xff0c 也就是最外层 xff0c 也就是边缘节点 它处理的流量是其他应用服务器处理流量的数倍 xff0c 甚至是几个数量级 在应用场景下所有的问题都会被放大 所以有必要去了解ma
  • 海康威视SDK 整合到springboot(二)

    上篇连接 xff1a 海康威视SDK告警上传功能整合到springboot xff08 一 xff09 上篇的只是兼容Windows系统 xff0c 此篇写兼容windos和Linux的一个整合 还是下载好sdk xff0c 将所需的so文
  • JS手写防抖与节流

    1 概念 xff1a 防抖 xff1a 指定内只执行一次 xff0c 如果指定时间内再次被触发 xff0c 则重新开始计时 实现主要需要利用闭包 xff0c 定时器 xff0c arguments和this指向 xff0c 立即执行 节流
  • QT 读取txt文件的几种方法

    废话不说直接上代码 xff11 xff0e 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 QString displayString QFile file 34 home alvin text txt 34 if
  • socket本地多进程通信基本使用方法和示例

    目录 前言 xff1a socket是什么 socket基本原理框图 socket基本函数 1 socket 函数 2 bind 函数 3 connect 函数 4 listen 函数 5 accept 函数 6 read write se