UNIX环境高级编程学习之第十六章网络IPC:套接字 - 非阻塞的Socket通信Select模型(多路复用), 实用Socket通信模板。
2010-11-23 16:40
886 查看
UNIX环境高级编程学习之第十六章网络IPC:套接字 - 非阻塞的Socket通信Select模型,多路复用, 实用Socket通信模板。
/* User:Lixiujie * Date:20101123 * Desc:Unix(Linux)非阻塞的Socket通信Select模型,多路复用,TCP服务器端, 向客户端发送响应信息。 * File:tcp_server_select.c * System:Ubuntu 64bit * gcc tcp_server_select.c tcp_server_select * tcp_server_select 7878 */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> /* socket bind listen connect accept send recv */ #include <arpa/inet.h> /* htons ntohs htonl ntohl inet_addr inet_ntoa */ #include <netinet/in.h> /* sockaddr_in */ #define BUFLEN 1024 #define QLEN 10 /* 传送信息结构体 */ typedef struct _MyMsg{ char szCmd[16];/* message command * RE_LINK:test link request * RESP_LINK:test link response * RE_EXIT: exit request * RESP_TEXT: exit response * RE_DATA: data request * RESP_DATA: data response */ int iLen; /* message data length*/ char szData[0];/* message data */ }MyMsg; /* 信息处理 */ MyMsg * MsgProcess(MyMsg *pMsgIn){ char szBuf[BUFLEN] = { 0x00 }; char szTmp[BUFLEN] = { 0x00 }; MyMsg *pMsg = NULL; FILE *fp; if (strcmp(pMsgIn->szCmd, "RE_LINK") == 0){ pMsg = (MyMsg *)malloc(sizeof(MyMsg)); memset(pMsg, 0, sizeof(MyMsg)); strcpy(pMsg->szCmd, "RESP_LINK"); }else if (strcmp(pMsgIn->szCmd, "RESP_LINK") == 0){ }else if (strcmp(pMsgIn->szCmd, "RE_EXIT") == 0){ pMsg = (MyMsg *)malloc(sizeof(MyMsg)); memset(pMsg, 0, sizeof(MyMsg)); strcpy(pMsg->szCmd, "RESP_TEXT"); }else if (strcmp(pMsgIn->szCmd, "RESP_TEXT") == 0){ }else if (strcmp(pMsgIn->szCmd, "RE_DATA") == 0){ memset(szBuf, 0, BUFLEN); strncpy(szBuf, pMsgIn->szData, pMsgIn->iLen); if ((fp = popen(szBuf, "r")) == NULL){ memset(szBuf, 0, BUFLEN); sprintf(szBuf, "error: %s/n", strerror(errno)); }else{ memset(szTmp, 0, BUFLEN); while (fgets(szTmp, BUFLEN, fp) != NULL){ strcat(szBuf, szTmp); memset(szTmp, 0, BUFLEN); } pclose(fp); } pMsg = (MyMsg *)malloc(sizeof(MyMsg)+ strlen(szBuf)+1); memset(pMsg, 0, sizeof(MyMsg)); strcpy(pMsg->szCmd, "RESP_DATA"); pMsg->iLen = strlen(szBuf)+1; strcpy(pMsg->szData, szBuf); }else if (strcmp(pMsgIn->szCmd, "RESP_DATA") == 0){ } return pMsg; } /* Socket结构体 */ typedef struct _SockNode{ int sock; struct sockaddr_in addr; struct _SockNode *pNext; }SockNode; /* create SockNode */ SockNode* createSockNode(int sock, struct sockaddr_in *pAddr){ SockNode *p = NULL; if ((p = (SockNode *)malloc(sizeof(SockNode))) != NULL){ p->sock = sock; memcpy(&(p->addr), pAddr, sizeof(struct sockaddr_in)); p->pNext = NULL; } return p; } /* add SockNode from list */ void addSockNodeList(SockNode *head, SockNode *node){ SockNode *p = head; while (p->pNext != NULL){ p = p->pNext; } p->pNext = node; } /* delete SockNode from list * return head */ SockNode* deleteSockNodeList(SockNode *head, int sock){ SockNode *p = head, *pPrevious = p; while (p != NULL){ if (p->sock == sock){ if (p != pPrevious){ pPrevious->pNext = p->pNext; }else{ head = p->pNext; } free(p); break; } pPrevious = p; p = p->pNext; } return head; } /* select SockNode from list * return head */ SockNode* selectSockNodeList(SockNode *head, int sock){ SockNode *p = head, *pPrevious = p; while (p != NULL){ if (p->sock == sock){ return p; } p = p->pNext; } return NULL; } /* maximumly sock from list */ int maxSockNodeList(SockNode *head){ SockNode *p = head; int maxsock = -1; while (p != NULL){ maxsock = maxsock > p->sock ? maxsock : p->sock; p = p->pNext; } return maxsock; } /* create tcp server */ int initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen){ int fd; int err = 0, iSockAttrOn = 1; /* 创建 */ if ((fd = socket(addr->sa_family, type, 0)) < 0){ return -1; } /* 端口复用 */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &iSockAttrOn, sizeof(iSockAttrOn) ) < 0){ err = errno; goto errout; } /* 绑定 */ if (bind(fd, addr, alen) < 0){ err = errno; goto errout; } /* 监听数 */ if (SOCK_STREAM == type || SOCK_SEQPACKET == type){ if (listen(fd, qlen) < 0) { err = errno; goto errout; } } return fd; errout: close(fd); errno = err; return -1; } int main(int argc, char *argv[]){ if (argc != 2){ printf("arg err!/n"); return -1; } int sefd, clfd, ret, len; char szBuf[BUFLEN]; SockNode *head = NULL,*node = NULL; /* socket 监听链表 */ struct sockaddr_in se_addr,cl_addr; socklen_t alen = sizeof(struct sockaddr); /* 设置服务IP和端口 */ memset((void *)&se_addr, 0, alen); se_addr.sin_family = AF_INET; se_addr.sin_addr.s_addr = INADDR_ANY;// inet_addr("0.0.0.0"); se_addr.sin_port = htons(atoi(argv[1])); if ((sefd = initserver(SOCK_STREAM, (struct sockaddr *)&se_addr, alen, QLEN)) < 0){ printf("initserver err=%s!/n", strerror(errno)); return -1; } printf("initserver OK !/n"); head = createSockNode(sefd, &se_addr); fd_set rdset; /* struct timeval timeout = {3, 0}; */ /* server 不设置超时 */ while (1){ FD_ZERO(&rdset); node = head; while(node != NULL){ FD_SET(node->sock, &rdset); node = node->pNext; } ret = select(maxSockNodeList(head) + 1, &rdset, NULL, NULL, NULL); if (ret < 0){ printf("select err=%s!/n", strerror(errno)); while (head != NULL){ node = head; head = head->pNext; close(node->sock); free(node); } return -1; }else if (0 == ret) { /* 不可能出现 */ printf("select timeout!/n"); sleep(1); continue; } node = head; while(node != NULL){ if (FD_ISSET(node->sock, &rdset) != 0){ if (node == head){ alen = sizeof(struct sockaddr); memset((void *)&cl_addr, 0 , alen); clfd = accept(node->sock, (struct sockaddr*)&cl_addr, &alen); if (clfd < 0){ printf("accept err=%s!/n", strerror(errno)); while (head != NULL){ node = head; head = head->pNext; close(node->sock); free(node); } return -1; } printf("Client connect:ip=%s, port=%d /n", inet_ntoa(cl_addr.sin_addr), ntohs(cl_addr.sin_port)); addSockNodeList(head, createSockNode(clfd, &cl_addr)); }else{ memset(szBuf, 0, BUFLEN); ret = recv(node->sock, szBuf, BUFLEN, 0); if (ret < 0){ printf("recv Client err=%s, ip=%s, port=%d!/n", strerror(errno), inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port)); close(node->sock); head = deleteSockNodeList(head, node->sock); } else if (0 == ret){ printf("recv Client exit, ip=%s, port=%d!/n", inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port)); close(node->sock); head = deleteSockNodeList(head, node->sock); } else { MyMsg *msgRecv = (MyMsg *)szBuf; msgRecv->iLen = ntohl(msgRecv->iLen);/* 转换成本机字节序 */ MyMsg *msgSend = NULL; /* 预处理 */ if (strcmp(msgRecv->szCmd, "RE_LINK") == 0){ printf("recv Client RE_LINK, ip=%s, port=%d!/n", inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port)); msgSend = MsgProcess(msgRecv); /* 实际处理 */ if (msgSend != NULL){ len = msgSend->iLen; msgSend->iLen = htonl(msgSend->iLen); /* 转换成网络字节序 */ memset(szBuf, 0, BUFLEN); memcpy(szBuf, msgSend, sizeof(MyMsg) + len); send(node->sock, szBuf, sizeof(MyMsg) + len, 0); printf("send Client %s, ip=%s, port=%d!/n", msgSend->szCmd, inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port)); free(msgSend); msgSend = NULL; } }else if (strcmp(msgRecv->szCmd, "RESP_LINK") == 0){ printf("recv Client RESP_LINK, ip=%s, port=%d!/n", inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port)); }else if (strcmp(msgRecv->szCmd, "RE_EXIT") == 0){ printf("recv Client RE_EXIT, ip=%s, port=%d!/n", inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port)); msgSend = MsgProcess(msgRecv); /* 实际处理 */ if (msgSend != NULL){ len = msgSend->iLen; msgSend->iLen = htonl(msgSend->iLen); /* 转换成网络字节序 */ memset(szBuf, 0, BUFLEN); memcpy(szBuf, msgSend, sizeof(MyMsg) + len); send(node->sock, szBuf, sizeof(MyMsg) + len, 0); printf("send Client %s, ip=%s, port=%d!/n", msgSend->szCmd, inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port)); free(msgSend); msgSend = NULL; } close(node->sock); head = deleteSockNodeList(head, node->sock); }else if (strcmp(msgRecv->szCmd, "RESP_TEXT") == 0){ printf("recv Client RESP_TEXT, ip=%s, port=%d!/n", inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port)); close(node->sock); head = deleteSockNodeList(head, node->sock); }else if (strcmp(msgRecv->szCmd, "RE_DATA") == 0){ printf("recv Client RE_DATA, ip=%s, port=%d, data:%s!/n", inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port), msgRecv->szData); msgSend = MsgProcess(msgRecv); /* 实际处理 */ if (msgSend != NULL){ len = msgSend->iLen; msgSend->iLen = htonl(msgSend->iLen); /* 转换成网络字节序 */ memset(szBuf, 0, BUFLEN); memcpy(szBuf, msgSend, sizeof(MyMsg) + len); send(node->sock, szBuf, sizeof(MyMsg) + len, 0); printf("send Client %s, ip=%s, port=%d, data:%s!/n", msgSend->szCmd, inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port), len > 0 ? msgSend->szData : ""); free(msgSend); msgSend = NULL; } }else if (strcmp(msgRecv->szCmd, "RESP_DATA") == 0){ printf("recv Client RESP_DATA, ip=%s, port=%d, data:%s!/n", inet_ntoa(node->addr.sin_addr), ntohs(node->addr.sin_port), msgRecv->szData); } }/* recv */ }/* node != head */ }/* if (FD_ISSET(node->sock, &rdset) != 0){ */ node = node->pNext; }/* node != NULL */ }/* while 1 */ while (head != NULL){ node = head; head = head->pNext; close(node->sock); free(node); } return 0; }
/* User:Lixiujie * Date:20101123 * Desc:Unix(Linux)非阻塞的Socket通信Select模型,多路复用,TCP客户端, 向服务端发送请求信息,接收响应信息。 * 可以在发送ls uptime pwd 等简单的显示命令 * File:tcp_client_select.c * System:Ubuntu 64bit * gcc tcp_client_select.c tcp_client_select * tcp_client_select 127.0.0.1 7878 */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> /* socket bind listen connect accept send recv */ #include <arpa/inet.h> /* htons ntohs htonl ntohl inet_addr inet_ntoa */ #include <netinet/in.h> /* sockaddr_in */ #include <pthread.h> /* multithreading */ #define BUFLEN 1024 /* 传送信息结构体 */ typedef struct _MyMsg{ char szCmd[16];/* message command * RE_LINK:test link request * RESP_LINK:test link response * RE_EXIT: exit request * RESP_TEXT: exit response * RE_DATA: data request * RESP_DATA: data response */ int iLen; /* message data length*/ char szData[0];/* message data */ }MyMsg; /* 信息处理 */ MyMsg * MsgProcess(MyMsg *pMsgIn){ char szBuf[BUFLEN] = { 0x00 }; char szTmp[BUFLEN] = { 0x00 }; MyMsg *pMsg = NULL; FILE *fp; if (strcmp(pMsgIn->szCmd, "RE_LINK") == 0){ pMsg = (MyMsg *)malloc(sizeof(MyMsg)); memset(pMsg, 0, sizeof(MyMsg)); strcpy(pMsg->szCmd, "RESP_LINK"); }else if (strcmp(pMsgIn->szCmd, "RESP_LINK") == 0){ }else if (strcmp(pMsgIn->szCmd, "RE_EXIT") == 0){ pMsg = (MyMsg *)malloc(sizeof(MyMsg)); memset(pMsg, 0, sizeof(MyMsg)); strcpy(pMsg->szCmd, "RESP_TEXT"); }else if (strcmp(pMsgIn->szCmd, "RESP_TEXT") == 0){ }else if (strcmp(pMsgIn->szCmd, "RE_DATA") == 0){ memset(szBuf, 0, BUFLEN); strncpy(szBuf, pMsgIn->szData, pMsgIn->iLen); if ((fp = popen(szBuf, "r")) == NULL){ memset(szBuf, 0, BUFLEN); sprintf(szBuf, "error: %s/n", strerror(errno)); }else{ memset(szTmp, 0, BUFLEN); while (fgets(szTmp, BUFLEN, fp) != NULL){ strcat(szBuf, szTmp); memset(szTmp, 0, BUFLEN); } pclose(fp); } pMsg = (MyMsg *)malloc(sizeof(MyMsg)+ strlen(szBuf)+1); memset(pMsg, 0, sizeof(MyMsg)); strcpy(pMsg->szCmd, "RESP_DATA"); pMsg->iLen = strlen(szBuf)+1; strcpy(pMsg->szData, szBuf); }else if (strcmp(pMsgIn->szCmd, "RESP_DATA") == 0){ } return pMsg; } int recvProcess(int sefd){ fd_set rdset; struct timeval timeout = {5, 0}; char szBuf[BUFLEN] = { 0x00 }; int ret, len; FD_ZERO(&rdset); FD_SET(sefd, &rdset); ret = select(sefd + 1, &rdset, NULL, NULL, &timeout); if (ret < 0){ printf("select err:%s/n", strerror(errno)); exit(-1); }else if (0 == ret){ memset(szBuf, 0, BUFLEN); strcpy(szBuf, "RE_LINK"); send(sefd, szBuf, strlen(szBuf) + sizeof(MyMsg), 0); printf("select timeout send: RE_LINK/n"); recvProcess(sefd); return -1; }else{ memset(szBuf, 0, BUFLEN); ret = recv(sefd, szBuf, BUFLEN, 0); if (ret < 0){ printf("recv err:%s/n", strerror(errno)); close(sefd); exit(-1); } else if (0 == ret){ printf("recv server close!/n"); close(sefd); exit(-1); } else { MyMsg *msgRecv = (MyMsg *)szBuf; msgRecv->iLen = ntohl(msgRecv->iLen);/* 转换成本机字节序 */ MyMsg *msgSend = NULL; /* 预处理 */ if (strcmp(msgRecv->szCmd, "RE_LINK") == 0){ printf("recv Server RE_LINK!/n"); msgSend = MsgProcess(msgRecv); /* 实际处理 */ if (msgSend != NULL){ len = msgSend->iLen; msgSend->iLen = htonl(msgSend->iLen); /* 转换成网络字节序 */ memset(szBuf, 0, BUFLEN); memcpy(szBuf, msgSend, sizeof(MyMsg) + len); send(sefd, szBuf, sizeof(MyMsg) + len, 0); printf("send Server %s,/n", msgSend->szCmd); free(msgSend); msgSend = NULL; } }else if (strcmp(msgRecv->szCmd, "RESP_LINK") == 0){ printf("recv Server RESP_LINK!/n"); }else if (strcmp(msgRecv->szCmd, "RE_EXIT") == 0){ printf("recv Server RE_EXIT!/n"); msgSend = MsgProcess(msgRecv); /* 实际处理 */ if (msgSend != NULL){ len = msgSend->iLen; msgSend->iLen = htonl(msgSend->iLen); /* 转换成网络字节序 */ memset(szBuf, 0, BUFLEN); memcpy(szBuf, msgSend, sizeof(MyMsg) + len); send(sefd, szBuf, sizeof(MyMsg) + len, 0); printf("send Server %s!/n", msgSend->szCmd); free(msgSend); msgSend = NULL; } close(sefd); exit(0); }else if (strcmp(msgRecv->szCmd, "RESP_TEXT") == 0){ printf("recv Server RESP_TEXT!/n"); close(sefd); exit(0); }else if (strcmp(msgRecv->szCmd, "RE_DATA") == 0){ printf("recv Server RE_DATA, data:%s!/n", msgRecv->szData); msgSend = MsgProcess(msgRecv); /* 实际处理 */ if (msgSend != NULL){ len = msgSend->iLen; msgSend->iLen = htonl(msgSend->iLen); /* 转换成网络字节序 */ memset(szBuf, 0, BUFLEN); memcpy(szBuf, msgSend, sizeof(MyMsg) + len); send(sefd, szBuf, sizeof(MyMsg) + len, 0); printf("send Server %s, data:%s!/n", msgSend->szCmd, len > 0 ? msgSend->szData : ""); free(msgSend); msgSend = NULL; } }else if (strcmp(msgRecv->szCmd, "RESP_DATA") == 0){ printf("recv Server RESP_DATA, data:%s!/n", msgRecv->szData); } } } return 0; } int main(int argc, char *argv[]){ if (argc != 3){ printf("arg err!/n"); return -1; } int sefd, ret, len; char szBuf[BUFLEN]; struct sockaddr_in se_addr, my_addr; MyMsg *pMsg; socklen_t alen = sizeof(struct sockaddr); /* 设置服务端的IP和端口 */ memset((void *)&se_addr, 0, alen); se_addr.sin_family = AF_INET; se_addr.sin_addr.s_addr = inet_addr(argv[1]); se_addr.sin_port = htons(atoi(argv[2])); if ((sefd = socket(se_addr.sin_family, SOCK_STREAM, 0)) < 0){ printf("socket err:%s/n", strerror(errno)); return -1; } if (connect(sefd, (struct sockaddr *)&se_addr, alen) < 0){ printf("connect err:%s/n", strerror(errno)); return -1; } alen = sizeof(struct sockaddr); memset((void *)&my_addr, 0, alen); getsockname(sefd, (struct sockaddr *)&my_addr, &alen); printf("connect OK, 本机IP:%s, Port:%d/n", inet_ntoa(my_addr.sin_addr), ntohs(my_addr.sin_port)); while (1){ memset(szBuf, 0, BUFLEN); printf("Input data:"); gets(szBuf); if (strncmp(szBuf, "link", 4) == 0){ memset(szBuf, 0, BUFLEN); strcpy(szBuf, "RE_LINK"); send(sefd, szBuf, strlen(szBuf) + sizeof(MyMsg), 0); printf("Send Server CMD: RE_LINK/n"); recvProcess(sefd); }else if (strncmp(szBuf, "exit", 4) == 0){ memset(szBuf, 0, BUFLEN); strcpy(szBuf, "RE_EXIT"); send(sefd, szBuf, strlen(szBuf) + sizeof(MyMsg), 0); printf("Send Server CMD: RE_EXIT/n"); recvProcess(sefd); }else if (strlen(szBuf) > 0){ pMsg = (MyMsg *)malloc(sizeof(MyMsg) + strlen(szBuf)+1); strcpy(pMsg->szCmd, "RE_DATA"); pMsg->iLen = strlen(szBuf)+1; strcpy(pMsg->szData, szBuf); len = pMsg->iLen; pMsg->iLen = htonl(pMsg->iLen); /* 转换成网络字节序 */ memset(szBuf, 0, BUFLEN); memcpy(szBuf, pMsg, sizeof(MyMsg) + len); send(sefd, szBuf, sizeof(MyMsg) + len, 0); printf("Send Server CMD: RE_DATA, data:%s/n", pMsg->szData); free(pMsg); recvProcess(sefd); }else{ printf("Error: Input err!/n"); } } return 0; }
相关文章推荐
- UNIX环境高级编程学习之第十六章网络IPC:套接字 - 非阻塞的Socket通信EPoll模型(多路复用), 实用Socket通信模板
- UNIX环境高级编程学习之第十六章网络IPC:套接字 - 非阻塞的Socket通信Poll模型(多路复用), 实用Socket通信模板
- UNIX环境高级编程学习之第十六章网络IPC:套接字 - 简单TCP Socket 通信
- UNIX环境高级编程学习之第十六章网络IPC:套接字 - 简单UDP Socket 通信
- UNIX环境高级编程学习之第十六章网络IPC:套接字 - 套接字选项的使用 (心跳检测、绑定地址复用)
- Unix环境高级编程(十七)网络IPC套接字
- UNIX环境高级编程-第16章- 网络IPC:套接字 - 二
- UNIX环境高级编程(第16章 网络IPC:套接字)
- UNIX环境高级编程 第16章 网络IPC:套接字
- (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字
- Unix 环境高级编程 (APUE) 之 网络 IPC:套接字
- unix环境编程学习笔记---------套接字------socket------客户端
- UNIX环境高级编程学习之第十章信号-信号集的操作,让进程阻塞SIGQUIT信号
- [网络编程]_[Socket]_[Socket 阻塞模式(blocking)下的 I/O模型(model) 之 Select 模型(model)初探]
- [网络编程]_[Socket]_[Socket 阻塞模式(blocking)下的 I/O模型(model) 之 Select 模型(model)初探]
- unix环境高级编程-------socket(套接字)
- UNIX环境高级编程学习之第十章信号-用信号和非局部转移函数写非阻塞的IO函数
- Linux网络通信编程(套接字模型TCP\UDP与IO多路复用模型select\poll\epoll)
- Linux网络通信编程(套接字模型TCP\UDP与IO多路复用模型select\poll\epoll)
- UNIX环境高级编程学习之第十五章进程间通信 - 通过半双工匿名管道实现父子进程通信