您的位置:首页 > 理论基础 > 计算机网络

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐