UNIX环境高级编程学习之第十六章网络IPC:套接字 – 非阻塞的Socket通信Select模型(多路复用), 实用Socket通信模板。

Linux/Unix C/C++ xiujie 250℃ 0评论 已收录

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




喜欢 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址