【环球播资讯】一种跨设备实现多进程间通信的方法!
设计思路:
(1)协议选择
由于Unix Domain传输速率大消耗资源少,但它只适用于本地之间传输,AF_INET Domain 消耗资源多,传输相对速率较低。为了高效实现跨设备多进程间通讯,可以同时使用Unix Domain 和 AF_INET Domain进程系统进程间通信。本地进程使用Unix Domain传输,远程设备使用AF_INET传输,为保证命令消息的可靠发送和接收,可以选择TCP传输。
(2)多进程间通信实现
要现实某个进程往其他任意一个进程间发送数据,中间必须建立一个服务端,服务端用来做数据路由,用来减少网络端口的连接同时简化各进程间数据的接收和发送。另外还可以通过路由实现广播的功能。
(相关资料图)
(3)命令消息格式设计
在实际应用中,多进程间的通信一般是用来实现各进程间的命令消息交互,为了保证命令消息的正确和完整,一般会对命令消息进行封装,这样也方便接收端在接收到数据的时候进行命令的解析。该命令消息的格式可以定义如下:
基本的通信网络模型如下:
功能实现:
(1)服务端(Router)
对于TCP连接,可以通过IP和端口来确定绑定地址,对于Unix Domain客户端,可以通过路径名来绑定地址。地址定义和绑定如下,这里预定义了20本地进程(客户端),两个远程设备,每个设备10个进程(客户端):
/*************************************************************Copyright (C),lcb0281at163.com lcb0281atgmail.com*FileName: ipc_common.h*BlogAddr: https://blog.csdn.net/li_wen01*Description: socket进程间通信数据结构及参数定义包括跨设备间TCP进程间通信和本地Unix Domain Socket进程间通信*Date: 2019-08-03*Author: Caibiao Lee*Version: V1.0*Others:*History:***********************************************************/#ifndef _IPC_COMMON_H_#define _IPC_COMMON_H_/**跨设备TCP socket进程间通信**/#define MAX_EXTARN_DEV_NUM 2 /**最大连接的网络设备数**/#define EACH_TCP_DEV_MAX_CLIENT_NUM 10 /**每个外接网络设备客户端数**/#define TCP_SERVER_PORT 6666 /**TCP连接服务端IP端口**//**TCP连接最大支持客户端数**/#define TCP_SERVER_LISTEN_MAX_NUM ((MAX_EXTARN_DEV_NUM)*(EACH_TCP_DEV_MAX_CLIENT_NUM))#define TCP_SERVER_IP"192.168.1.111"#define TCP_CLIENT_DEVICE1_IP"192.168.1.111" /**网络设备1 IP地址**/#define TCP_CLIENT_DEVICE2_IP"192.168.1.112" /**网络设备2 IP地址**/#define TCP_CLIENT_DEVICE1_NO1#define TCP_CLIENT_DEVICE2_NO2/**网络设备各客户端TCP端口**/#define TCP_DEVICE_CLIENT0_POART9000#define TCP_DEVICE_CLIENT1_POART9001#define TCP_DEVICE_CLIENT2_POART9002#define TCP_DEVICE_CLIENT3_POART9003#define TCP_DEVICE_CLIENT4_POART9004#define TCP_DEVICE_CLIENT5_POART9005#define TCP_DEVICE_CLIENT6_POART9006#define TCP_DEVICE_CLIENT7_POART9007#define TCP_DEVICE_CLIENT8_POART9008#define TCP_DEVICE_CLIENT9_POART9009#define TCP_DEVICE_CLIENT_MAX_POART 9009/**本地Unix Domain Socket进程间通信**/#define MAX_UDS_CLIENT_NUM 20 /**最大socket域客户端数,对应最大本地通讯进程数**/#defineSERVER_PATH"../tmp/server_socket" /**socket域服务端文件**/#define CLIENT_PACHT "../tmp/client_socket" /**socket域客户端文件前缀**//**本地客户端模块序号定义**/#define CLIENT_MIN_ADDR1#define LOCAL_CLIENT_1_ADDR 1#define LOCAL_CLIENT_2_ADDR 2#define LOCAL_CLIENT_3_ADDR 3#define LOCAL_CLIENT_4_ADDR 4#define LOCAL_CLIENT_5_ADDR 5#define LOCAL_CLIENT_6_ADDR 6#define LOCAL_CLIENT_7_ADDR 7#define LOCAL_CLIENT_8_ADDR 8#define LOCAL_CLIENT_9_ADDR 9#define LOCAL_CLIENT_10_ADDR 10#define LOCAL_CLIENT_11_ADDR 11#define LOCAL_CLIENT_12_ADDR 12#define LOCAL_CLIENT_13_ADDR 13#define LOCAL_CLIENT_14_ADDR 14#define LOCAL_CLIENT_15_ADDR 15#define LOCAL_CLIENT_16_ADDR 16#define LOCAL_CLIENT_17_ADDR 17#define LOCAL_CLIENT_18_ADDR 18#define LOCAL_CLIENT_19_ADDR 19#define LOCAL_CLIENT_MAX_ADDR 19/**网络设备1客户端模块序号定义**/#define DEV_CLIENT_MIN_ADDR 20#define DEV1_CLIENT_0_ADDR 20#define DEV1_CLIENT_1_ADDR 21#define DEV1_CLIENT_2_ADDR 22#define DEV1_CLIENT_3_ADDR 23#define DEV1_CLIENT_4_ADDR 24#define DEV1_CLIENT_5_ADDR 25#define DEV1_CLIENT_6_ADDR 26#define DEV1_CLIENT_7_ADDR 27#define DEV1_CLIENT_8_ADDR 28#define DEV1_CLIENT_9_ADDR 29/**网络设备1客户端模块序号定义**/#define DEV2_CLIENT_0_ADDR 30#define DEV2_CLIENT_1_ADDR 31#define DEV2_CLIENT_2_ADDR 32#define DEV2_CLIENT_3_ADDR 33#define DEV2_CLIENT_4_ADDR 34#define DEV2_CLIENT_5_ADDR 35#define DEV2_CLIENT_6_ADDR 36#define DEV2_CLIENT_7_ADDR 37#define DEV2_CLIENT_8_ADDR 38#define DEV2_CLIENT_9_ADDR 39#define DEV_CLIENT_MAX_ADDR 39#define CLIENT_MAX_ADDR 39extern const char * gc_au8DeviceNoMap[MAX_EXTARN_DEV_NUM]; extern const unsigned int gc_as32DeviceModuleMap[TCP_SERVER_LISTEN_MAX_NUM][3];
服务端server.c实现代码比较长,这里就不贴出来了,有兴趣的可以到我GitHub上查看:https://github.com/licaibiao/IPC_Socket
(2)客户端(各进程)
为方便客户端对消息命令的处理,客户端设计成每次接收到的数据是一个完整的命令消息,并且只有一条命令消息。为方便客户端的使用,将客户端的网络连接和网络状态检测同时封装到客户端数据接收和数据发送两个接口里面。比如在数据发送的时候,会去判断连接是否建立获取连接已经断开,如果网络异常则重新建立连接。
客户端ipc_interface.h接口定义如下
/*************************************************************Copyright (C),lcb0281at163.com lcb0281atgmail.com*FileName: ipc_interface.c*BlogAddr: https://blog.csdn.net/li_wen01*Description:客户端网络连接,数据收发,消息解析函数接口定义实现*Date: 2019-08-03*Author: Caibiao Lee*Version: V1.0*Others:*History:***********************************************************/#ifndef _IPC_INTERFACE_H_#define _IPC_INTERFACE_H_#include "ipc_common.h"#include "ipc_msgstruct.h"/**获取流水号**/int IPCP_Arch_Msg_AnalyzeGetFlowNum();/**获取应答流水号**/int IPCP_Arch_Msg_AnalyzeGetACKResult(ARCH_MSG_S *pstMsg);/**获取流水号地址**/int IPCP_Arch_Msg_AnalyzeGetRecFlow(ARCH_MSG_S *pstMsg);/**获取源地址**/int IPCP_Arch_Msg_ChangeSrcAddr(ARCH_MSG_S *pstMsg,unsigned char SrcAddr);/**获取目标地址**/int IPCP_Arch_Msg_ChangeTargAddr(ARCH_MSG_S *pstMsg,unsigned char TargAddr);/**获取源地址**/int IPCP_Arch_Msg_AnalyzeGetSrcAddr(ARCH_MSG_S *pstMsg);/**获取目标地址**/int IPCP_Arch_Msg_AnalyzeGetTargAddr(ARCH_MSG_S *pstMsg);/**获取消息ID**/int IPCP_Arch_Msg_AnalyzeGetCmdID(ARCH_MSG_S *pstMsg);/**获取内容长度**/int IPCP_Arch_Msg_AnalyzeGetLen(ARCH_MSG_S *pstMsg);/**获取消息内容开始位置**/void IPCP_Arch_Msg_PlatformStartP(unsigned char ** p, unsigned char* Data);/**发送数据**/int IPCP_Arch_Msg_PackSend(int s32ModuleAddr, MSG_PACK_S *pstMsg);/**读取数据**/int IPCP_Arch_Msg_Recv(int s32ModuleAddr,ARCH_MSG_S *pstMsg);#endif
(3)命令消息封装
为了更好地发送和接收命令消息,应该将命令消息基于网络传输协议之上再进行一层消息的封装,添加消息头标签,源地址目的地址和校验等信息。为了各进程间消息的更好识别和传输,应该对每条命令的数据结构进行定义,这样在解析的时候才不会出现参数对应不上的问题。我这里预定义了几个命令消息,用来测试该方法的稳定性。
ipc_msgstruct.h/*************************************************************Copyright (C),lcb0281at163.com lcb0281atgmail.com*FileName: ipc_msgstruct.h*BlogAddr: https://blog.csdn.net/li_wen01*Description:命令消息结构体定义和解析*Date: 2019-08-03*Author: Caibiao Lee*Version: V1.0*Others:*History:***********************************************************/#ifndef _IPC_MSGSTRUCT_H_#define _IPC_MSGSTRUCT_H_/**数据结构重定义**/typedef unsigned char byte;typedef signed char INT8S;typedef signed int INT32S;typedef unsigned char BYTE;typedef unsigned short WORD;typedef unsigned int DWORD;typedef unsigned char INT8U;typedef unsigned short INT16U;typedef unsigned int INT32U;#define IPCP_TRUE 0#define IPCP_FALSE1#define ARRAY_SIZE(_A) (sizeof(_A) / sizeof((_A)[0]))/**通讯协议位定义**//************************************************************************************//** | 2Byet| Byet | Byet | 2Byet | 2*Byet |2Byet |N*Byet | Byet | 2Byet | **//** | 0xa5a5 | 源地址| 目标地址| 流水号 | 消息ID |消息长度 |消息体 | 校验 | 0x5a5a | **//** | 0 1 | 2 | 3 | 4 5 | 6 7 | 8 9 |10 | 10+N | 10+N+1 | **//************************************************************************************/#define MSG_SRC_ADDR (2)#define MSG_TAR_ADDR (3)#define MSG_SERIAL_NUM_ADDR (4)#define MSG_CMID_ADDR (6)#define MSG_MSG_LEN_ADDR (8)#define MSG_ACK_CMID_ADDR (10)#define MSG_ACK_SERIAL_NUM_ADDR (12)#define MSG_ACK_RES_ADDR (14)#define MSG_CONTENT_OFFSET (10) /**消息内容开始位置**/#define MSG_HEAD_LEN (10)#define MSG_END_LEN (3)#define MSG_ARCH_MSG_LEN (13)#define QUEUE_MSG_HEAD 0xa5a5#define QUEUE_MSG_END 0x5a5atypedef struct MsgPack{ unsigned char SrcAddr; unsigned char TargAddr; unsigned short Len; unsigned char *Data; unsigned short CmdId;}MSG_PACK_S;#define MSG_TEXT_SIZE (2048)typedef struct ARCH_MSG{ unsigned int MsgLen; unsigned char SomeText[MSG_TEXT_SIZE];}ARCH_MSG_S;/*通用IPCP指令*/#define QUEUE_DEBUG_CMD1 (0x0001)#define QUEUE_DEBUG_CMD2 (0x0002)#define QUEUE_DEBUG_CMD3 (0x0003)#define QUEUE_DEBUG_CMD4 (0x0004)#define QUEUE_DEBUG_CMD5 (0x0005)#define QUEUE_DEBUG_CMD6 (0x0006)#define QUEUE_DEBUG_CMD7 (0x0007)#define QUEUE_DEBUG_CMD8 (0x0008)#define QUEUE_DEBUG_CMD9 (0x0009)#define QUEUE_DEBUG_CMDA (0x000A)#define QUEUE_DEBUG_MAX_CMD (0x000A)/**消息定义**/typedef struct{DWORD u32Alarm; /* 报警 */DWORD u32Status; /* 状态 */DWORD u32Latitude; /* 纬度,百万分之一度 */ DWORD u32Longtitude; /* 经度,百万分之一度 */ WORDu16Altitude; /* 高程,米 */WORDu16SpeedX10; /* gps速度,1/10 km/h */WORD u16Direct; /* 方向 */ BYTE arrCardNo[16]; /* 机动车牌号码 */WORD u16SensorSpeed; /* 脉冲速度,1/10 km/h */BYTE u8CarCor; /* 车牌颜色 */}__attribute__ ((__packed__))MSG_0X0001_S;typedef struct{unsigned int u32FileId; /**文件id,不为0时,按文件id查找**/ unsigned char u8DeleteFlag;/**删除标志:0:保留;1:删除**/ unsigned char u8StopFlag;/**停止上传标志:0:保留;1:停止上传**/ unsigned char u8srcPlat; /**下发命令的平台地址**/}__attribute__ ((__packed__))MSG_0X0002_S;typedef struct{unsigned char u8Type; /**0人脸识别结果,1人头个数识别**/ unsigned char u8Result; /**type为0时,0成功,1失败**/ }__attribute__ ((__packed__))MSG_0X0003_S;typedef struct{unsigned char u8Interval;/**时间间隔**/ unsigned int u32Duration; /**持续时间**/ }__attribute__ ((__packed__))MSG_0X0004_S;typedef struct{ DWORD u32MultiId;/**多媒体ID,小端内存**/ WORD u16TotalNum;/**下发拍照的总数**/ WORD u16CurNum;/**当前图片序号**/ BYTE u8PlatAddr;/**平台地址**/}__attribute__ ((__packed__))MSG_0X0005_S;typedef struct{DWORD u32ModeEvent; /**休眠唤醒事件:1:休眠,2:唤醒*/}__attribute__ ((__packed__))MSG_0X0006_S;typedef struct{DWORD u32ParaId; /* 参数id: 0x1000010C*/BYTE u8ParaLen; /* 参数长度: 4 */unsigned long long u64AlarmFlag;/* bit*/}__attribute__ ((__packed__))MSG_0X0007_S;typedef struct{DWORD u32ParaId; /* 参数id: 0x1000010C*/BYTE u8ParaLen; /* 参数长度: 4 */DWORD u32TimeOut; /* 单位为秒*/}__attribute__ ((__packed__))MSG_0X0008_S;typedef struct{DWORD u32ParaId; /* 参数id: 0x30000007*/BYTE u8ParaLen; /* 参数长度: 4 */DWORD u32Payload; /* 参数值:96:h264编码, 265:h265编码*/}__attribute__ ((__packed__))MSG_0X0009_S;typedef struct{BYTEu8ParaNum; /* 参数总数 */}__attribute__ ((__packed__))MSG_0X000A_S;typedef int (*HandleHook_Func)(unsigned char*, unsigned short,unsigned char);typedef struct { unsigned int u32MsgID; HandleHook_Func pFuncHandle;}MSG_HANDLE_HOOK_S;int IPCPMsg_Debug_Cmd1(unsigned char *pu8SomeText, unsigned short u16Len, unsigned char u8SrcAddr);int IPCPMsg_Debug_Cmd2(unsigned char *pu8SomeText, unsigned short u16Len, unsigned char u8SrcAddr);int IPCPMsg_Debug_Cmd3(unsigned char *pu8SomeText, unsigned short u16Len, unsigned char u8SrcAddr);int IPCPMsg_Debug_Cmd4(unsigned char *pu8SomeText, unsigned short u16Len, unsigned char u8SrcAddr);int IPCPMsg_Debug_Cmd5(unsigned char *pu8SomeText, unsigned short u16Len, unsigned char u8SrcAddr);int IPCPMsg_Debug_Cmd6(unsigned char *pu8SomeText, unsigned short u16Len, unsigned char u8SrcAddr);int IPCPMsg_Debug_Cmd7(unsigned char *pu8SomeText, unsigned short u16Len, unsigned char u8SrcAddr);int IPCPMsg_Debug_Cmd8(unsigned char *pu8SomeText, unsigned short u16Len, unsigned char u8SrcAddr);int IPCPMsg_Debug_Cmd9(unsigned char *pu8SomeText, unsigned short u16Len, unsigned char u8SrcAddr);int IPCPMsg_Debug_CmdA(unsigned char *pu8SomeText, unsigned short u16Len, unsigned char u8SrcAddr);#endif
测试:
为了测试该方法的可靠和稳定性,有新建2个本地进程和2个远程设备进程,让他们随机时间随机往某个进程发送命令,看是否会出现命令消息丢失或是解析错误的问题。其中本地一个客户端的实现如下:
/*************************************************************Copyright (C),lcb0281at163.com lcb0281atgmail.com*FileName: local_client1.c*BlogAddr: https://blog.csdn.net/li_wen01*Description:本地模块进程1*Date: 2019-08-03*Author: Caibiao Lee*Version: V1.0*Others:*History:***********************************************************/#include #include #include #include #include #include #include #include "ipc_interface.h"#include "ipc_msgstruct.h"#include "ipc_common.h"#define CLIENT_MODULE_ADDR LOCAL_CLIENT_1_ADDR#define LOCAL1_DELAY_FOR_DEBUG_US (1000*1000)/**消息处理**/MSG_HANDLE_HOOK_S g_astLocalMsgTable[] ={{QUEUE_DEBUG_CMD1, IPCPMsg_Debug_Cmd1},{QUEUE_DEBUG_CMD2, IPCPMsg_Debug_Cmd2},{QUEUE_DEBUG_CMD3, IPCPMsg_Debug_Cmd3},{QUEUE_DEBUG_CMD4, IPCPMsg_Debug_Cmd4},{QUEUE_DEBUG_CMD5, IPCPMsg_Debug_Cmd5},{QUEUE_DEBUG_CMD6, IPCPMsg_Debug_Cmd6},{QUEUE_DEBUG_CMD7, IPCPMsg_Debug_Cmd7},{QUEUE_DEBUG_CMD8, IPCPMsg_Debug_Cmd8},{QUEUE_DEBUG_CMD9, IPCPMsg_Debug_Cmd9},{QUEUE_DEBUG_CMDA, IPCPMsg_Debug_CmdA}, {0,NULL},};/**********************************linux ctrl + C 会产生 SIGINT信号接收到SIGINT 信号进入该函数**********************************/void stop(int signo){int i = 0;printf(" stop \n");_exit(0);}/*********************************************当客户端断开连接的时候,在服务端socket send进程可以收到收到信号SIGPIPE,收到SIGPIPE信号进入该函数结束创建的线程。**********************************************/void signal_pipe(int signo){}/******************************************************** Function: ClientSendMsg Description: 客户端(某一进程)发送数据包Input:s32TargModuleAddr : 需要发送到的模块地址OutPut: noneReturn: 0 成功;非0 异常Others:Author: Caibiao LeeDate:2019-08-03*********************************************************/int ClientSendMsg(int s32TargModuleAddr){int l_s32Res = 0;MSG_PACK_S l_stMsg = {0};MSG_0X0001_S l_stMsgSend = {0};if((s32TargModuleAddrLOCAL_CLIENT_MAX_ADDR)){printf("%s %d input para error %d \n",__FUNCTION__,__LINE__,s32TargModuleAddr);return -1;}l_stMsgSend.arrCardNo;l_stMsgSend.u16Altitude = 0x66;l_stMsgSend.u16Direct = 0x11;l_stMsgSend.u16SensorSpeed= 0x12;l_stMsgSend.u16SpeedX10 = 0x13;l_stMsgSend.u32Alarm = 0xbb;l_stMsgSend.u32Latitude = 0xaa;l_stMsgSend.u32Longtitude = 0x15;l_stMsgSend.u32Status = 0x01;l_stMsgSend.u8CarCor = 0x08;l_stMsg.CmdId = QUEUE_DEBUG_CMD1;l_stMsg.Data = (unsigned char*)&l_stMsgSend;l_stMsg.Len = sizeof(MSG_0X0001_S);l_stMsg.SrcAddr = CLIENT_MODULE_ADDR;l_stMsg.TargAddr = s32TargModuleAddr;IPCP_Arch_Msg_PackSend(CLIENT_MODULE_ADDR,&l_stMsg);return 0;}/******************************************************** Function: ClientRecvMsg Description: 客户端(某一进程)接收数据包,并对数据包进行解析Input:OutPut: noneReturn: 0 成功;非0 异常Others:Author: Caibiao LeeDate:2019-08-03*********************************************************/int ClientRecvMsg(void){int i = 0;int l_s32RecvLen = 0;int l_s32SrcAddr = 0;int l_s32CmdId = 0;int l_s32TextLen = 0;int l_s32FlowNum = 0;int l_u32IPCPMsgNum = 0;unsigned char *l_pu8MsgBody = NULL;ARCH_MSG_S l_stMsg = {0};l_s32RecvLen = IPCP_Arch_Msg_Recv(CLIENT_MODULE_ADDR,&l_stMsg);if(l_s32RecvLen>0){IPCP_Arch_Msg_PlatformStartP(&l_pu8MsgBody, l_stMsg.SomeText);l_u32IPCPMsgNum = ARRAY_SIZE(g_astLocalMsgTable);l_s32SrcAddr = IPCP_Arch_Msg_AnalyzeGetSrcAddr(&l_stMsg);l_s32CmdId = IPCP_Arch_Msg_AnalyzeGetCmdID(&l_stMsg);l_s32TextLen = IPCP_Arch_Msg_AnalyzeGetLen(&l_stMsg);l_s32FlowNum = IPCP_Arch_Msg_AnalyzeGetRecFlow(&l_stMsg);printf("l_s32SrcAddr = %d \n",l_s32SrcAddr);printf("l_s32CmdId = %d \n",l_s32CmdId);printf("l_s32TextLen = %d \n",l_s32TextLen);printf("l_s32FlowNum = %d \n",l_s32FlowNum);for(i = 0; i < l_u32IPCPMsgNum; i++){if(l_s32CmdId == g_astLocalMsgTable[i].u32MsgID){if(NULL!=g_astLocalMsgTable[i].pFuncHandle){g_astLocalMsgTable[i].pFuncHandle(l_pu8MsgBody, l_s32TextLen,l_s32SrcAddr);}break;}}}return 0;}int main(int argc,char *argv[]){int l_s32Delay = 0;int l_s32Addr = 0;int l_as32SendAddr[3] ={0};l_as32SendAddr[0] = LOCAL_CLIENT_2_ADDR;l_as32SendAddr[1] = DEV1_CLIENT_1_ADDR,l_as32SendAddr[2] = DEV1_CLIENT_2_ADDR;/**注册 SIGPIPE信号**/signal(SIGPIPE,signal_pipe); /**注册SIGINT 信号**/signal(SIGINT,stop); while(1){l_s32Addr = IPCP_GetRandomReal(0,3);if((l_s32Addr>=0)&&(l_s32Addr<=2)){ClientSendMsg(l_as32SendAddr[l_s32Addr]);}ClientRecvMsg();l_s32Delay = IPCP_GetRandomReal(50,100);usleep(l_s32Delay*1000);}return 0;}
实际运行结果如下:
上面测试是以50~100ms随机发送一包数据来测试,运行24小时后未检测到异常。
总结:
(1)阻塞与非阻塞问题
实际客户端在接收和发送,应该是需要非阻塞的模式,正常的数据接收和发送不能影响客户端原本的业务逻辑处理。在非阻塞状态下数据的接收和发送都需要特别的注意。
在发送的时候,因为是非阻塞的,当对方接收缓存满了的时候,发送端会收到EAGAIN的错误码,该错误码是让你进行数据的重新发送。在我这里我是设计发送失败会重新发送3遍,然后3次发送后还是失败,那么这包数据就会被丢弃。
在接收的时候,我们需要去判断对方网络是否还处于连接的状态,可以使用select实现,也可以通过接收PIPE信号来判断,为了更好的数据处理,在我这里是使用select来判断对方网络是否已经断开连接。
(2)缓存大小问题
每建立一个socket,在连接或是绑定之前,我们都可以设置该socket连接的收发缓存大小,可以根据实际应用的发送峰值来判断应该设置多大的缓存。在我Ubuntu16.04系统下,默认的TCP和UnixDomain收发缓存大小如下:
biao@ubuntu:~/test/ipcp_socket/server$ ./servercreate unix domin socket lpthread successcreate TCP socket lpthread successcreate read write lpthread seccessTCP SO_RCVBUF = 87380TCP SO_SNDBUF = 16384server waiting for tcp client connectUnix Domain SO_RCVBUF = 212992Unix Domain SO_SNDBUF = 212992server waiting for unix domain client connect
工程下载:
以上,完整代码文件如下:
biao@ubuntu:~/test/ipcp_socket$ tree.├── common│ ├── ipc_common.c│ ├── ipc_common.h│ ├── ipc_interface.c│ ├── ipc_interface.h│ ├── ipc_msgstruct.c│ └── ipc_msgstruct.h├── device1│ ├── device1_client1.c│ ├── device1_client2.c│ └── Makefile├── local│ ├── local_client1.c│ ├── local_client2.c│ └── Makefile├── server│ ├── Makefile│ └── server.c└── tmp ├── client_socket1 ├── client_socket2 └── server_socket5 directories, 17 filesbiao@ubuntu:~/test/ipcp_socket$
在 liwen01
公众号中回复 网络编程
获取工程代码,本章代码工程名为:ipcp_socket_20190815_V2.tar.gz
本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。
注意
猜你喜欢:
谈谈嵌入式软件的兼容性!
我是韦东山老师的忠实粉丝!
标签:
为您推荐
广告
- 【环球播资讯】一种跨设备实现多进程间通信的方法!
- 天天速讯:出海SLG洗牌?莉莉丝、IGG、点点互动新游数据曝光
- motomb525(motomb860)
- @云南考生,2023年普通高校招生宣传咨询会等你来_全球最新
- 【环球新要闻】什么是鼻息肉
- 环球今日讯!婆婆误转2500元给陌生人,民警帮助当天追回
- 侨心向党,新街口地区归侨赞歌迎七一 焦点简讯
- 新资讯:鞍钢股份:随着船舶海工行业高质量发展持续推进,高端船用钢品种将获得较高发展红利
- 环球最新:深圳5月新发放普惠小微贷款加权平均利率同比下降0.93个百分点
- 探讨未来汽车产业发展趋势 2023未来汽车先行者大会聚焦智能电动新变革 每日观点
- 研究联盟学术简报(2023年第1期)
- 福州潮宏基今日黄金价格查询(2023年6月21日) 世界快报
- 湖南村卫生室诊疗信息系统正式上线,可实时完成医保报销
- 环球即时:官方回应停车5分钟收5元:车库是私人的,允许收管理费
- 排骨烧什么菜比较好吃_排骨和什么菜搭配最好
- 菊乃香清酒|“健康、微醺、适口”才是清酒佳品
- 写给祖国母亲的寄语(写给祖国母亲的一封信)
- 本周五起 两条北三县通勤公交线路调整
- 青岛地税网上办税综合业务平台(青岛市地税局网上办税厅 环球资讯
- 昆仑万维午后大跌超15% 成交金额超66亿元-天天消息
- 1工信部:我国已建立结构完整、有机协同的新能源汽车产业体系
- 2水生态2022年上半年净利33.18万同比增长247.14% 工程项目增加-热资讯
- 3陕西省新能源电池材料回收利用协会成立大会及揭牌仪式隆重举行!_当前快播
- 4天天报道:逃离后室escape the backrooms联机进不去/加不进房间/最多几个人
- 5环球实时:6月21日内蒙古地区氢氟酸市场价格暂稳
- 6世界时讯:蔚来获阿布扎比投资机构11亿美元投资:持股7%,有权提名董事
- 7博世中国总裁不看好车企造手机,李书福笑着回应了
- 8多家巴媒:36岁苏亚雷斯已告知格雷米奥管理层未来几周退役
- 9渡马镇:小积分换出大治理
- 10【天天报资讯】京东金条审核会给联系人打电话吗?这些情况需要注意!
- 1周口老兵:志愿服务解民忧 助力三夏夺丰收-精彩看点
- 2衣褶画法攻略 不信你还学不会!_天天新消息
- 3买普通焊机还是买无气气保焊-环球百事通
- 4巴基斯坦博士后带妻女参加武大毕业典礼:决定留在中国生活,并对自己的未来许下寄语
- 5每日热讯!惊悚犯罪片《宵禁》:如何在迷失生活中,寻找亲情的救赎之光
- 6天天快看点丨白酒进入调整周期?中国酒业协会:短期不乐观 长期不悲观!
- 7世界新动态:不同年龄段的常见眼病,你都知道吗?眼科医生呼吁:定期眼部检查能有效避免致盲眼病发生
- 8【全球新视野】“618”交易总额提升,最终达成7987亿元
- 9每日讯息!人面不知何处去原文
- 10雅安到成都多少时间(雅安到成都多少公里)
广告
- 雷军:我当上金山CEO不是我厉害 基本情况讲解 天天百事通
- 创业板新股海看股份上市首日高开,现涨超24%
- 高速不免费!日均车流量250万辆!河北高速交警发布端午出行最新提示
- AI大模型火爆 行业大咖共话AI新发展产业新机遇
- 热议:补肾壮阳药哪种最好最有效_补肾壮阳药哪种最好
- 速递!PTA价格维持承压震荡 下游终端消费表现一般
- 当前视讯!XD东吴证:6月19日融资买入5244.73万元,融资融券余额16.52亿元
- 上游直击股东会丨西南证券将坚持稳中求进 拟高比例分红近2亿元-独家焦点
- 青骄第二课堂注册登录官网(青娇第二课堂注册登录)
- 微博会员年卡年内最低价 双重优惠仅需50元
- 为什么快充会变成普通充电
- 年报披露时间规定2020_年报披露时间
- 天天即时看!华坪县气象台发布暴雨橙色预警信号【Ⅱ级/严重】【2023-06-20】
- 全球球精选!中国城市人才吸引力排名:京沪深居前三
- 每日时讯!尽管梅西缺席,但印尼球迷仍在比赛中高喊“梅西”致敬传奇
- 世界焦点!海峡论坛吸引台商放眼更广阔大陆市场
- 握住当下的幸福:生活感悟卷 每日报道
- 一加Ace 2 Pro把骁龙8 Gen2下放 太强了! 天天热头条
- 房屋评估价格计算房产税_房屋评估价查询-世界时快讯
- 每日快播:喜马拉雅申请AI开放平台商标