实验五、多线程并发服务器编程(2)

2018-12-29 22:56

}

void DieWithSystemMessage(const char *msg) { perror(msg); exit(1);

}

/****************************************************************************** 文件名:TCPServerUtility.c

******************************************************************************/ #include #include #include #include #include #include \

static const int MAXPENDING = 5; //常量不是宏定义

int SetupTCPServerSocket(const char *service) { struct addrinfo addrCriteria; // Criteria for address match memset(&addrCriteria, 0, sizeof(addrCriteria)); // Zero out structure

addrCriteria.ai_family = AF_UNSPEC; // Any address family

addrCriteria.ai_flags = AI_PASSIVE; // Accept on any address/port addrCriteria.ai_socktype = SOCK_STREAM; // Only stream sockets addrCriteria.ai_protocol = IPPROTO_TCP; // Only TCP protocol struct addrinfo *servAddr; // List of server addresses

int rtnVal = getaddrinfo(NULL, service, &addrCriteria, &servAddr); if (rtnVal != 0) DieWithUserMessage(\ int servSock = -1; struct addrinfo *addr;

for (addr = servAddr; addr != NULL; addr = addr->ai_next) { servSock = socket(addr->ai_family, addr->ai_socktype,addr->ai_protocol); if (servSock < 0) continue; if ((bind(servSock, addr->ai_addr, addr->ai_addrlen) == 0) &&(listen(servSock, MAXPENDING) == 0)) {

struct sockaddr_storage localAddr; socklen_t addrSize = sizeof(localAddr); if (getsockname(servSock, (struct sockaddr *) &localAddr, &addrSize) < 0) DieWithSystemMessage(\ break; } close(servSock); servSock = -1; } freeaddrinfo(servAddr); return servSock; }

int AcceptTCPConnection(int servSock) {

int clntSock; /* 客户连接返回的套接字 */ struct sockaddr_in echoClntAddr; /* 客户地址*/ unsigned int clntLen;

clntLen = sizeof(echoClntAddr);

/* 等待客户端连接 */

if ((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr,&clntLen)) < 0) { printf(\ exit(1); }

printf(\ return clntSock; }

void HandleTCPClient(int clntSocket) { char buffer[BUFSIZE]; ssize_t numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0); if (numBytesRcvd < 0) DieWithSystemMessage(\ while (numBytesRcvd > 0)

{ //将收到的信息返回给客户端 if(send(clntSocket, buffer, numBytesRcvd, 0) < 0) DieWithSystemMessage(\ numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0); if (numBytesRcvd < 0) DieWithSystemMessage(\ }

close(clntSocket); }

/***************************************************************************** 文件名:AddressUtility.c

******************************************************************************/ #include #include #include #include

void PrintSocketAddress(const struct sockaddr *address, FILE *stream) { if (address == NULL || stream == NULL) return;

void *numericAddress; char addrBuffer[INET6_ADDRSTRLEN]; in_port_t port; switch (address->sa_family) {

case AF_INET: //IPV4 numericAddress = &((struct sockaddr_in *) address)->sin_addr; port = ntohs(((struct sockaddr_in *) address)->sin_port); break;

case AF_INET6: //IPV6 numericAddress = &((struct sockaddr_in6 *) address)->sin6_addr; port = ntohs(((struct sockaddr_in6 *) address)->sin6_port); break;

default: fputs(\

return; } if (inet_ntop(address->sa_family, numericAddress, addrBuffer, sizeof(addrBuffer)) == NULL) fputs(\ else { fprintf(stream, \往流中写字符串 if (port != 0) fprintf(stream, \ //u%表示无符号整数输出 } }

bool SockAddrsEqual(const struct sockaddr *addr1, const struct sockaddr *addr2) { if (addr1 == NULL || addr2 == NULL) return addr1 == addr2;

else if (addr1->sa_family != addr2->sa_family) return false;

else if (addr1->sa_family == AF_INET) { struct sockaddr_in *ipv4Addr1 = (struct sockaddr_in *) addr1; struct sockaddr_in *ipv4Addr2 = (struct sockaddr_in *) addr2; return ipv4Addr1->sin_addr.s_addr == ipv4Addr2->sin_addr.s_addr && ipv4Addr1->sin_port == ipv4Addr2->sin_port; }

else if (addr1->sa_family == AF_INET6) { struct sockaddr_in6 *ipv6Addr1 = (struct sockaddr_in6 *) addr1; struct sockaddr_in6 *ipv6Addr2 = (struct sockaddr_in6 *) addr2; return memcmp(&ipv6Addr1->sin6_addr, &ipv6Addr2->sin6_addr,sizeof(struct in6_addr)) == 0 && ipv6Addr1->sin6_port == ipv6Addr2->sin6_port; } else return false; }

/****************************************************************************** 文件名:TCPEchoServer-Thread.c

******************************************************************************/ #include #include

#include #include \

void *ThreadMain(void *arg); //线程块

struct ThreadArgs { int clntSock; };

int main(int argc, char *argv[]) { if(argc != 2) DieWithSystemMessage(\运行命令和参数错误!\

char *service = argv[1];

unsigned int processLimit = atoi(argv[2]);

int servSock = SetupTCPServerSocket(service); if ( servSock<0)

DieWithSystemMessage(\创建套接字失败!\

for(;;) { int clntSock = AcceptTCPConnection(servSock); struct ThreadArgs *threadArgs = (struct ThreadArgs *) malloc(sizeof(struct ThreadArgs)); if(threadArgs == NULL) DieWithSystemMessage(\分配内存失败!\ threadArgs->clntSock = clntSock; pthread_t threadID; int returnValue = pthread_create(&threadID, NULL, ThreadMain, threadArgs); if(returnValue != 0) DieWithSystemMessage(\ printf(\ } }

void *ThreadMain(void *threadArgs) { pthread_detach( pthread_self() );

int clntSock = ((struct ThreadArgs *)threadArgs)->clntSock; free(threadArgs); HandleTCPClient(clntSock); return NULL; }

3)运行结果 首先编译链接完成后产生serv和 cli两个程序,编译链接服务器和客户端程序的指令请大家参照前面的案例给出。完成编译链接后先启动服务器程序serv,如图3所示,然后再运行客户端程序,如图4所示。服务器打印子进程ID,客户端收到服务器返回的信息。可以同时运行多个客户端程序。建议客户端和服务器运行于不同的物理机器上。

图3、服务器运行界面

图4、客户端运行界面

3、思考题

1)请使用多线程实现服务器和客户端之间不受发送接收顺序约束的“聊天”。 2)简要描述父线程与子线程之间的关系。

三、小结

本次实验使我们熟悉Linux线程的一些基本概念以及多进程程序与多线程程序的区别,熟悉了如何创建线程,熟悉了函数pthread_create的用法以及多线程的特点。特别要注意非标准库函数的编译链接方法。


实验五、多线程并发服务器编程(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:用友ERP供应链管理系统实验报告

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: