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;
}