linux简单进程间socket通信

socket多用于网络通信,但将服务地址设为本机地址之后,即可实现本机进程间socket通信,利用socket可以在进程间方便地传输数据。

在linux平台上还支持AF_UNIX通信,而不必设定本机地址,这种socket通信类型在windows平台上并不适用。

下面模拟三个进程间利用socket通信,server进程负责接收客户端进程1和2的通信请求并且将通信内容转交给对端。对于server端利用两个线程分别接收两个客户端的连接请求,并且开了两个socket,这种方式只是简单的模拟实现,是效率低下的一种方式。示例代码如下:

服务进程server

</pre><p></p><pre name="code" class="cpp">#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h> //for memset
#include <sys/stat.h>
#include <sys/param.h>
#include <stdarg.h>

// 设定端口号
#define RPC_PORT_CSDK	6666
#define RPC_PORT_UI		6665
#define BUFF_SIZE 		1024
#define LOG_FILE			"daemon.log"

char recv_ui[BUFF_SIZE];
char recv_csdk[BUFF_SIZE];

// 通过可变参数写日志文件
void writeLog(const char* format, ...)
{
	va_list argp;
	FILE* flog;

	va_start(argp, format);
	flog = fopen(LOG_FILE, "a");
	vfprintf(flog, format, argp);
	fclose(flog);
	va_end(argp);
}

void recvMessage(int fd, char* buf)
{
	int ret;
	if(buf == NULL)
	{
		writeLog("SERVER: recieve message buffer is null!\n");	
		return;
	}

	ret = recv(fd, buf, BUFF_SIZE, 0);
			buf[ret] = '\0';
		
	if(ret > 0)
	{
		if(buf == recv_csdk)
			writeLog("SERVER_CSDK: received %d message--%s\n", strlen(buf), buf);
		else
			writeLog("SERVER_UI: received %d message--%s\n", strlen(buf), buf);
	}
}

void sendMessage(int fd, const char* toWhom)
{
	if(toWhom == NULL)
	{
		writeLog("SERVER:	write to whom is null\n");
		return;
	}
	else if(toWhom == "UI")
	{
		if( strlen(recv_csdk) == 0)
		{
			return;
		}		
		else
		{
			recv_csdk[strlen(recv_csdk)] = '\0';
			send(fd, recv_csdk, strlen(recv_csdk), 0);
			writeLog("SERVER: write to fd %d message -- %s\n", fd, recv_csdk);
			memset(recv_csdk, 0, BUFF_SIZE);		
		}
	}
	else if(toWhom == "CSDK")
	{
		if( strlen(recv_ui) == 0)
		{
			return;
		}
		else
		{
			recv_ui[strlen(recv_ui)] = '\0';
			send(fd, recv_ui, strlen(recv_ui), 0);
			writeLog("SERVER: write to fd %d message %d bytes -- %s\n", fd, strlen(recv_ui), recv_ui);
			memset(recv_ui, 0, BUFF_SIZE);		
		}
	}
}

void initDaemon(void)
{
	pid_t pid;
	int i;

	if( (pid = fork()) < 0)
		writeLog("SERVER: daemon fork 1 failed!\n");

	else if(pid > 0)
		exit(0); // 退出父进程
	
	setsid();	//第一个子进程成为会话组长和进程组长, 并与控制终端分离
	
	if( (pid = fork()) < 0)
		writeLog("SERVER: daemon fork 2 failed!\n");

	else if( pid > 0)
		exit(0);	// 退出第一个子进程

	for( i=0; i<NOFILE; ++i)	//关闭打开的文件描述符
		close(i);

	//chdir("/tmp"); //改变工作目录到/tmp

	umask(0);	//重设创建文件掩码n 
	return;
}

void serveCSDK(void)
{
	int ret;
	char buff[BUFF_SIZE];
	
	fd_set readFds, testFds;

	int connFd, listenFd;;
	struct sockaddr_in serverAddr;

	// 创建socket
	listenFd = socket(AF_INET, SOCK_STREAM, 0);
	if( listenFd < 0)
	{
		writeLog("SERVER: create socket failed!\n");
		exit(EXIT_FAILURE);
	}

	// 设定服务端地址及端口
	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);	// INADDR_ANY--自动查找本机地址
	serverAddr.sin_port = htons(RPC_PORT_CSDK);

	// 绑定
	ret = bind(listenFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
	if(ret < 0)
	{
		writeLog("SERVER_CSDK: bind socket failed!\n");
		exit(EXIT_FAILURE);
	}
	
	// 监听
	ret = listen(listenFd, 10);	// 最大接受10个连接
	if( ret < 0)	
	{
		writeLog("SERVER_CSDK: listen socket failed!\n");
		exit(EXIT_FAILURE);
	}

	FD_ZERO(&readFds);
	FD_SET(listenFd, &readFds);
	
	while(1)
	{
		testFds = readFds;

		// 等待连接
		writeLog("SERVER_CSDK: waiting for connection ...\n");

		//ret = select(FD_SETSIZE, &testfds, (fd_set *)NULL, (fd_set *)NULL, )

		connFd = accept(listenFd, (struct sockaddr*)NULL, NULL);
		if( connFd  < 0 ) 
		{
			writeLog("SERVER_CSDK: accept socket failed!\n");
			exit(EXIT_FAILURE);
		}

		while(1)
		{
			recvMessage(connFd, recv_csdk);
			sendMessage(connFd, "CSDK");
		}
	}
}

void serveUI(void)
{
	int ret;
	char buff[BUFF_SIZE];

	int connFd, listenFd;;	
	struct sockaddr_in serverAddr;
	
	// 创建socket
	listenFd = socket(AF_INET, SOCK_STREAM, 0);
	if( listenFd < 0)
	{
		writeLog("SERVER: create socket failed!\n");
		exit(EXIT_FAILURE);
	}

	// 设定服务端地址及端口
	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);	// INADDR_ANY--自动查找本机地址
	serverAddr.sin_port = htons(RPC_PORT_UI);

	// 绑定
	ret = bind(listenFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
	if(ret < 0)
	{
		writeLog("SERVER_UI: bind socket failed!\n");
		exit(EXIT_FAILURE);
	}
	
	// 监听
	ret = listen(listenFd, 10);
	if( ret < 0)	// 最大接受10个连接
	{
		writeLog("SERVER_UI: listen socket failed!\n");
		exit(EXIT_FAILURE);
	}
	
	while(1)
	{
		// 等待连接
		writeLog("SERVER_UI: waiting for connection ...\n");

		connFd = accept(listenFd, (struct sockaddr*)NULL, NULL);
		if( connFd  < 0 ) 
		{
			writeLog("SERVER_UI: accept socket failed!\n");
			exit(EXIT_FAILURE);
		}

		while(1)
		{
			recvMessage(connFd, recv_ui);
			sendMessage(connFd, "UI");
		}
	}
}


int main(void)
{
	int ret;

	initDaemon();
	writeLog("SERVER: daemon create succeed\n");

	pthread_t th_csdk, th_ui;

	ret = pthread_create(&th_csdk, NULL, serveCSDK, NULL);
	if(ret != 0)
	{
		writeLog("SERVER: create csdk server thread failed!\n");		
		exit(EXIT_FAILURE);
	}
	
	// 脱离线程
	ret = pthread_detach(th_csdk);
	if(ret != 0)
	{
		writeLog("SERVER: detach the csdk thread failed!\n");
		exit(EXIT_FAILURE);
	}

	// 执行UI服务
	serveUI();
	
	return 0;
} 

客户进程1 process1

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h> //for memset
#include <sys/stat.h>
#include <sys/param.h>

// 设定端口号
#define RPC_PORT		6665
#define BUFF_SIZE		1024

int main(void)
{
	int ret;

	int socketServer, socketNew;
	int clientFd, connFd;	
	struct sockaddr_in serverAddr;

	// 创建socket
	clientFd = socket(AF_INET, SOCK_STREAM, 0);
	if( clientFd == -1)
	{
		printf("CLIENT: socket create failure!\n");
		exit(EXIT_FAILURE);
	}

	// 设定服务端地址及端口
	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);	// INADDR_ANY--自动查找本机地址
	serverAddr.sin_port = htons(RPC_PORT);
	
	ret = connect(clientFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
	if( ret < 0)
	{
		printf("CLIENT: connect failure!\n");
		exit(EXIT_FAILURE);
	}

	char sendBuf[BUFF_SIZE] = "Hello, I Am UI";
	char recvBuf[BUFF_SIZE];
	memset(recvBuf, 0, BUFF_SIZE);

	while(1)
	{
		ret = send(clientFd, sendBuf, strlen(sendBuf), 0);
		if(ret > 0)
			printf("CLIENT_UI: send message succeed!\n");

		ret = recv(clientFd, recvBuf, BUFF_SIZE, MSG_DONTWAIT);
		if(ret > 0)
			printf("CLIENT_UI: received message: %s\n", recvBuf);

		sleep(3);
	}	
	
	return 0;
}

客户进程2 process2

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h> //for memset
#include <sys/stat.h>
#include <sys/param.h>

// 设定端口号
#define RPC_PORT		6666
#define BUFF_SIZE		1024

int main(void)
{
	int ret;

	int socketServer, socketNew;
	int clientFd, connFd;	
	struct sockaddr_in serverAddr;

	// 创建socket
	clientFd = socket(AF_INET, SOCK_STREAM, 0);
	if( clientFd == -1)
	{
		printf("CLIENT_CSDK: socket create failure!\n");
		exit(EXIT_FAILURE);
	}

	// 设定服务端地址及端口
	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);	// INADDR_ANY--自动查找本机地址
	serverAddr.sin_port = htons(RPC_PORT);
	
	ret = connect(clientFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
	if( ret < 0)
	{
		printf("CLIENT_CSDK: connect failure!\n");
		exit(EXIT_FAILURE);
	}

	char sendBuf[BUFF_SIZE] = "Hello, I Am CSDK";
	char recvBuf[BUFF_SIZE];
	memset(recvBuf, 0, BUFF_SIZE);

	while(1)
	{
		ret = send(clientFd, sendBuf, strlen(sendBuf), 0);
		if(ret > 0)
			printf("CLIENT_CSDK: send message succeed!\n");

		ret = recv(clientFd, recvBuf, BUFF_SIZE, MSG_DONTWAIT);
		if(ret > 0)
			printf("CLIENT_CSDK: received message: %s\n", recvBuf);

		sleep(3);
	}	
	
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值