unix域协议(类TCP)实现本机进程间通讯

 1、服务器端程序:


ssize_t master_send(int fd, const void *buf, size_t len)
{
ssize_t bytes, total = 0;
const uint8_t *data = (typeof(data))buf;


while (len) {
bytes = write(fd, data, len);
if (bytes < 0){
if (errno == EINTR)
continue;
total = bytes;
break;
}
data  += bytes;
len   -= bytes;
total += bytes;
}

return total;
}




ssize_t master_recv(int fd, void *buf, size_t len)
{
ssize_t bytes, total = 0;
uint8_t *data = (typeof(data))buf;

while (len) {
bytes = read(fd, data, len);
if (bytes < 0){
if (errno == EINTR)
continue;
total = bytes;
break;
}
data  += bytes;
len   -= bytes;
total += bytes;
}

return total;
}


static int proc_msg(int ick, WnetClass_t *wc, T_APP_MSG *pstRecvMsg)
{
int istate = 0;
int idispinfo = 0;
int ierror = 0;
int iPid = -1;
int iDstPort = 0;
T_APP_MSG stSendMsg;
WnetPPPInfo_t *psWnetInfo = NULL;
int iRet = -1;


if (NULL == pstRecvMsg)
{
return -1;
}
memset(&stSendMsg,0x00, sizeof(stSendMsg));


switch(pstRecvMsg->msgType)
{


case E_MSG_NOTIFY_WNET_STOP:

debuging("wnet notify wnet stop\n");
break;

default:
debuging("msgType Error\n");
break;
}


master_send(ick, &stSendMsg, sizeof(stSendMsg));


return iRet;
}


/*检查文件是否存在没有则创建,unix域套接字的bind需要一个文件的路径名,所以最好先创建好*/

static void check_create_file(const char *pathname)
{
int mode = 0777;
int fd = -1;
if (NULL == pathname)
{
debuging("NULL == pathname\n");
return;
}

if (0 == access(pathname, F_OK))
{
return;
}



fd = open(pathname, O_CREAT, mode);
if (fd < 0)
{
debuging("open %s creat Failed\n", pathname);
return;
}
else
{
debuging("open %s creat Success\n", pathname);
close(fd);
return;
}


}

/*初始化,创建、绑定、监听*/

static int service_init(const char *filename)
{
int svrsk, len, retval;
struct sockaddr_un un;


//un.sun_family = AF_UNIX;

if ((svrsk = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
debuging("socket = failed, errno = %d\n", errno);
return -1;
}

unlink(filename);


memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, filename);
len = offsetof(struct sockaddr_un, sun_path) + strlen(filename);


if ((retval = bind(svrsk, (struct sockaddr *)&un, len)) < 0) 
{
debuging("bind Failed, errno = %d\n", errno);
goto err_server_init;
}

/*给文件名设置属性,很重要*/
chmod(filename, S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO);

if ((retval = listen(svrsk, LISTEN_QUEUE_LEN)) < 0)
{
debuging("listen Failed, errno = %d\n", errno);
goto err_server_init;
}

return svrsk;


err_server_init:
close(svrsk);
return retval; 
}

/*accept,阻塞等待数据的到来一边进行处理*/

static int service_accept(WnetClass_t *wc, const char *pathname, int svrsk)
{
int clisk, bytes;
socklen_t len;
struct sockaddr_un un;
T_APP_MSG reqpkt;
T_APP_MSG *reqdat;
debuging("svrsk = %d\n", svrsk);
while (1) {
len = sizeof(un);
clisk = accept(svrsk, (struct sockaddr *)&un, &len);
if (clisk >= 0) {
len -= offsetof(struct sockaddr_un, sun_path);
un.sun_path[len] = '\0';
current_lisk = clisk;
if (master_recv(clisk, &reqpkt, sizeof(reqpkt)) ==  sizeof(reqpkt)) 
{

/*处理数据函数*/
proc_msg(clisk, wc, &reqpkt);
}

close(clisk);   //关闭socket,以便等待再次的连接
clisk  = -1;
} else {
debuging("svrsk = %d\n", svrsk);
if (errno != EINTR)
debuging( "accept=%d",  clisk);
}

}


return 0;
}


/*把上面的三个函数整合在一起,第一个入参是用于后面处理数据使用*/

static int master_service(WnetClass_t *wc, const char *pathname)
{
int sk;
struct sigaction sa;

memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigpiple_handler;
sigaction( SIGPIPE, &sa, NULL);


check_create_file(pathname);
debuging("pathname = %s\n", pathname);

if ((sk = service_init(pathname)) < 0)
return sk;


service_accept(wc, pathname,sk);


close(sk);
return 0;
}

/*主程序直接调用maser_service便可,主线程会循环等待连接接收数据*/

int main(int argc, char *argv[])
{

WnetClass_t  *wc;
T_APP_MSG stSendMsg;
int iPort = -1;


debuging("%d\n",getpid());
wc = wnet_create();

master_service(wc, UNIX_FILE);


return 0;
}


2、客户端程序


int unix_socket_connect(void)
{
int sk, retval, on;
socklen_t len;
int iTimeOut = 2;
struct timeval  ts, tn, td;
struct sockaddr_un un;


if ((sk = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return sk;


/* Enable address reuse */
on = 1;
setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );


memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;


sprintf(un.sun_path, "%s/%05d.%d", UNIX_DOMAIN_PATH, gettid(), rand());


len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);


if ((retval = bind(sk, (struct sockaddr *)&un, len)) < 0)
{
debuging("retval = %d\n", retval);
goto err_connect_server;
}
chmod(un.sun_path, S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO);  //改变文件属性
unlink(un.sun_path);     //记着unlink掉不然会生成一个文件

memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, WNET_UNIX_FILE);
len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
getruntime(&ts, NULL);
while(1)
{
if (iTimeOut > 0) 
{
getruntime(&tn, NULL);
timersub(&tn, &ts, &td);
if (td.tv_sec >= iTimeOut)
{
debuging("Timeout\n");
close(sk);
sk = -1;
break;
}
}
if ((retval = connect(sk, (struct sockaddr *)&un, len)) < 0)
{
debuging("retval = %d\n", retval);
continue;
}


return sk;
}


err_connect_server:
close(sk);

return retval;
}

int main(int argc, char *argv[])
{

int iSocketHandle = -1;

int iRet = FAIL;

struct timeval  ts, tn, td;
int iTimeOut = 3; /*1S钟超时时间*/
T_APP_MSG stAppRecvData;
T_APP_MSG stAppSendData;

/*创建连接,后面要记着及时close掉,这个动作做完下个动作重新连接来收发数据*/
iSocketHandle = unix_socket_connect();

if(iSocketHandle < 0)
{
debuging("unix_socket_connect Created Failed\n");
return -1;
}
memset(&stAppSendData, 0x00, sizeof(stAppSendData));

debuging("unix_socket_connect Created Successed\n");
stAppSendData.appType = iPid;
stAppSendData.msgType = E_MSG_START_NOTFY_WNET_PORT;

iRet = master_send(iSocketHandle, &stAppSendData, sizeof(stAppSendData));
memset(&stAppRecvData, 0x00, sizeof(stAppRecvData));
getruntime(&ts, NULL);

while (1) 
{
/*超时时间到跳出默认3s钟*/
if (iTimeOut > 0) 
{
getruntime(&tn, NULL);
timersub(&tn, &ts, &td);
if (td.tv_sec   >= iTimeOut)
{
debuging("Timeout\n");
iRet = FAIL;
break;
}
}

iRet = master_recv(iSocketHandle, &stAppRecvData, sizeof(stAppRecvData));
if (E_MSG_WNET_OK == stAppRecvData.msgType)
{
debuging("stAppRecvData.msgType = %d\n", stAppRecvData.msgType);
iRet = SUCCESS;
break;
}

}


debuging("unix_socket_connect Start Close \n");
close(iSocketHandle);
return iRet;


return 0;
}


总结:

   服务器端记着是一直在accept等待,有数据来便进行数据的处理;

  客户端的程序是要记住每次创建连接后要及时close,这样就下次建立连接才能正常收发数据。



你可能感兴趣的:(tcp,bind,connect,listen,进程间通讯)