TCP程序设计(c语言课程设计)(3)

2019-03-03 14:19

} } return; } /*错误输出函数*/ void ErrorPrint(x) { printf(\} /*用户帮助函数*/ void userHelp() { printf(\ printf(\ printf(\ printf(\ printf(\ printf(\\\n\ printf(\ ExitProcess(-1); } 4) 循环控制模块

循环控制模块的功能是由LoopControl()函数实现的。具体步骤可参见10.3.3节中的函数功能描述其操作流程图可参见图10.4。

/*循环控制函数*/ int LoopControl(SOCKET listenfd, int isMultiTasking) { SOCKET acceptfd; struct sockaddr_in clientAddr; int err; int nSize; int serverNum = 0; HANDLE handles[MAX_SER]; int myID; /*服务次数小于最大服务次数*/ while (serverNum < maxService) { nSize = sizeof(clientAddr); /*接收客户端请求*/ acceptfd = accept(listenfd, (struct sockaddr *) &clientAddr, &nSize); /*如果接收失败*/ if (acceptfd == INVALID_SOCKET) { ErrorPrint(\ return 1; } /*接收成功*/ printf(\ inet_ntoa(clientAddr.sin_addr)); /*如果允许多任务执行*/ if (isMultiTasking) { /*创建一个新线程来执行任务,新线程的初始堆栈大小为1000,线程执行函数 是Service(),传递给Service()的参数为acceptfd*/ handles[serverNum] = CreateThread(NULL, 1000, (LPTHREAD_START_ROUTINE)Service, (LPVOID) acceptfd, 0, &myID); } else /*直接调用服务客户端的函数*/ Service((LPVOID) acceptfd); serverNum++; } if (isMultiTasking) { /*在一个线程中等待多个事件,当所有对象都被通知时函数才会返回,并且等待没有时间限制*/ err = WaitForMultipleObjects(maxService, handles, TRUE, INFINITE); printf(\ } return 0; } 5) 服务模块

服务模块的功能由函数Service()来实现。其功能主要是接收、判断来自客户端的数据,以及发送数据到客户端。Service()函数首先接收客户端发送来的数据,存放到缓冲区response中,然后判断接收到的数据是否和预定义的数据“HELLO SERVER”相同,如果相同则发送消息到客户端,并关闭套接字;否则,输出错误信息并关闭套接字。其实现流程图可参见图10.5。

/*服务函数*/ void Service(LPVOID lpv) { SOCKET acceptfd = (SOCKET) lpv; const char *msg = \ char response[4096]; /*用0初始化response[4096]数组*/ memset(response, 0, sizeof(response)); /*接收数据,存入response中*/ recv(acceptfd, response, sizeof(response), 0); /*如果接收到的数据和预定义的数据不同*/ if (strcmp(response, \ { printf(\ \ } else /*发送服务器端信息到客户端*/ send (acceptfd, msg, strlen(msg)+1, 0); /*关闭套接字*/ closesocket(acceptfd); } 6) 主函数

主函数控制着整个程序的流程,包括套接字的创建、绑定、侦听和释放,以及对各个模块中函数的调用等。其具体操作流程图可参见图10.2。

/*主函数*/ int main(int argc, char **argv) { SOCKET listenfd; int err; struct sockaddr_in serverAddr; struct hostent *ptrHost; initial(); GetArgments(argc,argv); InitSockets(); /*创建TCP流套接字,在domain参数为PF_INET的SOCK_STREAM套接口中,protocol参数为0意味 着告诉内核选择 IPPRPTP_TCP,这也意味着套接口将使用TCP/IP协议*/ listenfd = socket(PF_INET, SOCK_STREAM, 0); /*如果创建套接字失败*/ if (listenfd == INVALID_SOCKET) { printf(\ return 1; } /*如果是IP地址*/ if (atoi(hostName)) { /*将IP地址转换成32二进制表示法,返回32位二进制的网络字节序*/ u_long ip_addr = inet_addr(hostName); /*根据IP地址找到与之匹配的主机名*/ ptrHost = gethostbyaddr((char *)&ip_addr, sizeof(u_long), AF_INET); } /*如果是主机名*/ else /*根据主机名获取一个指向hosten的指针,该结构中包含了该主机所有的IP地址*/ ptrHost = gethostbyname(hostName); /*如果解析失败*/ if (!ptrHost) { ErrorPrint(\ return 1; } /*设置服务器地址*/ /*设置地址族为PF_INET*/ serverAddr.sin_family = PF_INET; /*将一个通配的Internet地址转换成无符号长整型的网络字节序数*/ serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); /*将端口号转换成无符号短整型的网络字节序数*/ serverAddr.sin_port = htons(port); /*将套接字与服务器地址绑定*/ err = bind(listenfd, (const struct sockaddr *) &serverAddr, sizeof(serverAddr)); /*如果绑定失败*/ if (err == INVALID_SOCKET) { ErrorPrint(\ return 1; } /*开始侦听,设置等待连接的最大队列长度为SOMAXCONN,默认值为5个*/ err = listen(listenfd, SOMAXCONN); /*如果侦听失败*/ if (err == INVALID_SOCKET) { ErrorPrint(\ return 1; } LoopControl(listenfd, 1); printf(\ /*释放Winscoket初始化时占用的资源*/ WSACleanup(); return 0; } 2. 客户端(client.c) 1) 程序预处理

与服务器一样,客户端的预处理也包括库文件的导入、头文件的加载和全局变量的定义。

/*导入库文件*/ #pragma comment(lib,\/*加载头文件*/ #include #include /*自定义函数*/ int InitSockets(void); void GetArgument(int argc, char **argv); void ErrorPrint(x); void userHelp(); /*定义全局变量*/ unsigned short port; char *hostName; 2) 初始化模块

因为不存在对全局变量赋初始值,所以客户端的初始化模块仅仅初始化Winsock,包括初始化套接字版本号加载Winsock库。

/*初始化Winsock函数*/ int InitSockets(void) { WSADATA wsaData; WORD sockVersion; int err;


TCP程序设计(c语言课程设计)(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:第四届“挑战杯”湖南工程学院大学生创业计划竞赛附件

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

马上注册会员

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