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,这样就下次建立连接才能正常收发数据。