【网络编程】利用I/O复用模型实现一个时间同步服务器
来源:互联网 发布:js控制下拉列表反显 编辑:程序博客网 时间:2024/06/03 06:42
实验要求:
1. 服务端采用I/O复用模型(select函数)接收客户端的时间同步请求;
2. 服务端采用单线程,但要能同时接收多客户端的连接请求,显示客户端IP和端口,并向其回送时间信息。
3. 客户端尝试同时使用UDP和TCP来实现。
注:借助I/O复用模型,用单线程达到多线程的效果
server:
// EchoTCPServer-select.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#undef UNICODE #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #include <stdlib.h> #include <stdio.h> #include<cstdio>#include<cstring>#include<iostream>#include<ctime>#include<time.h>using namespace std;// 连接到winsock2对应的lib文件: Ws2_32.lib #pragma comment (lib, "Ws2_32.lib") #define DEFAULT_BUFLEN 512 //默认缓冲区长度为512#define DEFAULT_PORT 27015 //默认服务器端口号为27015int _tmain(int argc, _TCHAR* argv[]){/////////////////////////////////////////udpWORD sockVersion = MAKEWORD(2, 2);WSADATA wsaDataudp;if (WSAStartup(sockVersion, &wsaDataudp) != 0){return 0;}SOCKET serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (serSocket == INVALID_SOCKET){printf("socket error !");WSACleanup();return 0;}sockaddr_in serAddr;serAddr.sin_family = AF_INET;serAddr.sin_port = htons(DEFAULT_PORT);serAddr.sin_addr.S_un.S_addr = INADDR_ANY;if (bind(serSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR){printf("bind error !");closesocket(serSocket);WSACleanup();return 0;}cout << "listening the client" << endl;sockaddr_in remoteAddr;int nAddrLen = sizeof(remoteAddr);int cnt = 0;char RecvBuffer[64];/////////////////////////////////////////tcp WSADATA wsaDatatcp; int iResult; SOCKET ServerSocket = INVALID_SOCKET; SOCKET AcceptSocket = INVALID_SOCKET; char recvbuf[DEFAULT_BUFLEN]; int recvbuflen = DEFAULT_BUFLEN; sockaddr_in addrClient;int addrClientlen = sizeof(sockaddr_in); // 初始化 Winsock iResult = WSAStartup(MAKEWORD(2,2), &wsaDatatcp); if (iResult != 0) { printf("WSAStartup failed with error: %d\n", iResult); return 1; } // 创建用于监听的套接字 ServerSocket = socket(AF_INET,SOCK_STREAM, IPPROTO_IP); if(ServerSocket == INVALID_SOCKET) { printf("socket failed with error: %ld\n", WSAGetLastError()); WSACleanup(); return 1; } // 为套接字绑定地址和端口号SOCKADDR_IN addrServ; addrServ.sin_family = AF_INET; addrServ.sin_port = htons(DEFAULT_PORT);// 监听端口为DEFAULT_PORT addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY); iResult = bind(ServerSocket,(const struct sockaddr*)&addrServ,sizeof(SOCKADDR_IN)); if (iResult == SOCKET_ERROR) { printf("bind failed with error: %d\n", WSAGetLastError()); closesocket(ServerSocket); WSACleanup(); return 1; } // 监听套接字 iResult = listen(ServerSocket, SOMAXCONN); if(iResult == SOCKET_ERROR) { printf("listen failed !\n"); closesocket(ServerSocket); WSACleanup(); return -1; } printf("TCP server starting\n");printf("UDP server starting\n");fd_set fdRead,fdSocket;fd_set fdReadudp, fdSocketudp;FD_ZERO(&fdSocketudp);FD_SET(serSocket, &fdSocketudp); FD_ZERO( &fdSocket );FD_SET( ServerSocket, &fdSocket);while( TRUE){//////udp/////fdReadudp = fdSocketudp;iResult = select(0, &fdReadudp, NULL, NULL, NULL);if (iResult > 0){//有网络事件发生//确定有哪些套接字有未决的I/O,并进一步处理这些I/Ofor (int i = 0; i < (int)fdSocketudp.fd_count; i++){if (FD_ISSET(fdSocketudp.fd_array[i], &fdReadudp)){if (fdSocketudp.fd_array[i] == serSocket){if (fdSocketudp.fd_count < FD_SETSIZE){memset(RecvBuffer, 0, sizeof(RecvBuffer));int Ret = recvfrom(serSocket, RecvBuffer, 64, 0, (sockaddr *)&remoteAddr, &nAddrLen);if (Ret < 0){cout << "receive error " << WSAGetLastError();continue;}RecvBuffer[Ret] = 0x00;cout << "接收到新的连接:ip: %s " << ++cnt << ": " << inet_ntoa(remoteAddr.sin_addr);cout << " post: " << remoteAddr.sin_port << endl;time_t t = time(0);char tmp[64];strftime(tmp, sizeof(tmp), "%Y/%m/%d %X", localtime(&t));cout << "send time : ";puts(tmp);//将本地时间发送给客户端 sendto(serSocket, tmp, sizeof(tmp), 0, (sockaddr *)&remoteAddr, nAddrLen);}else{printf("连接个数超限!\n");continue;}}}}}//tcp//通过select等待数据到达事件,如果有事件发生,select函数移除fdRead集合中没有未决I/O操作的套接字句柄,然后返回 fdRead = fdSocket;iResult = select( 0, &fdRead, NULL, NULL, NULL);if (iResult >0){//有网络事件发生//确定有哪些套接字有未决的I/O,并进一步处理这些I/Ofor (int i=0; i<(int)fdSocket.fd_count; i++){if (FD_ISSET( fdSocket.fd_array[i] ,&fdRead)){if( fdSocket.fd_array[i] == ServerSocket){if( fdSocket.fd_count < FD_SETSIZE){//同时复用的套接字数量不能大于FD_SETSIZE//有新的连接请求AcceptSocket = accept(ServerSocket,(sockaddr FAR*)&addrClient,&addrClientlen); if( AcceptSocket == INVALID_SOCKET) { printf("accept failed !\n"); closesocket(ServerSocket); WSACleanup(); return 1; }//增加新的连接套接字进行复用等待FD_SET( AcceptSocket, &fdSocket);printf("接收到新的连接:ip: %s ", inet_ntoa(addrClient.sin_addr));cout << "post: " << addrClient.sin_port << endl;time_t t = time(0);char tmp[64];strftime(tmp, sizeof(tmp), "%Y/%m/%d %X", localtime(&t));send(AcceptSocket, tmp, strlen(tmp), 0);cout << "send time :";puts(tmp);//将本地时间发送给客户端 }else{printf("连接个数超限!\n"); continue;}}else{//有数据到达memset(recvbuf,0,recvbuflen);iResult = recv( fdSocket.fd_array[i], recvbuf, recvbuflen, 0); if (iResult > 0) { //情况1:成功接收到数据printf("\nBytes received: %d\n", iResult); } else if (iResult == 0) {//情况2:连接关闭//printf("Current Connection closing...\n"); closesocket(fdSocket.fd_array[i]);FD_CLR(fdSocket.fd_array[i], &fdSocket);}else { //情况3:接收失败printf("recv failed with error: %d\n",WSAGetLastError() ); closesocket(fdSocket.fd_array[i]); FD_CLR(fdSocket.fd_array[i], &fdSocket);} }}}}else{printf("select failed with error: %d\n",WSAGetLastError() ); break; }} // cleanup closesocket(ServerSocket); WSACleanup(); return 0; }
client_tcp:
#include "stdafx.h" #include <stdio.h> #include <winsock2.h> #include <wincrypt.h>#include <time.h>#include <cstring>#include <iostream> #include <string.h> #pragma comment(lib, "user32.lib")#pragma comment(lib, "shlwapi.lib")#pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "crypt32.lib")const int MAX1 = 1000;using namespace std;int main(int argc, const char*argv[]){WORD sockVersion = MAKEWORD(2, 2);WSADATA wsaData;int error = WSAStartup(sockVersion, &wsaData);if (error){cout << "fail to startup" << GetLastError() << endl;WSACleanup();return 0;}SOCKET socketClient = socket(AF_INET, SOCK_STREAM, 0);if (socketClient == INVALID_SOCKET){cout << "socket error! " << GetLastError() << endl;WSACleanup();closesocket(socketClient);return 0;}char ip[20];memset(ip, 0, sizeof(ip));cout << "Please input the ip: ";gets_s(ip);cout << endl;sockaddr_in addrServer;addrServer.sin_addr.S_un.S_addr = inet_addr(ip);addrServer.sin_family = AF_INET;addrServer.sin_port = htons(27015);connect(socketClient, (SOCKADDR*)&addrServer, sizeof(SOCKADDR));//FileSend(socketClient);char revbuf[64]; memset(revbuf, 0, sizeof(revbuf));recv(socketClient,revbuf, 64, 0);puts(revbuf);closesocket(socketClient);getchar();return 0;}
client_udp:
#include "stdafx.h" #include <iostream>#include <stdio.h> #include <winsock2.h> #include <windows.h>using namespace std;#pragma comment(lib, "ws2_32.lib") const int MAX_IP_PATH = 15;const int MAX_BUFFER = 10240;const int NAME = 10240;int main(int argc, char* argv[]){WORD socketVersion = MAKEWORD(2, 2);WSADATA wsaData;if (WSAStartup(socketVersion, &wsaData) != 0){return 0;}SOCKET ClientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (ClientSocket == INVALID_SOCKET){cout << "Create Socket Failed::" << GetLastError() << endl;WSACleanup();return -1;}char IP_ADDRESS[MAX_IP_PATH];unsigned int PORT = 27015;cout << "connect IP:";cin >> IP_ADDRESS;cout << endl;sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(PORT);sin.sin_addr.S_un.S_addr = inet_addr(IP_ADDRESS);unsigned int msglen;char SendBuffer[64]="ask time";int len = sizeof(sin);cout << "asking time"<<endl;msglen = strlen(SendBuffer);sendto(ClientSocket, SendBuffer, strlen(SendBuffer), 0, (sockaddr *)&sin, len);int Ret;char RecvBuffer[64];Ret = recvfrom(ClientSocket, RecvBuffer, sizeof(RecvBuffer) , 0, (sockaddr *)&sin, &len);if (Ret <0){cout << "receive error:" << WSAGetLastError();closesocket(ClientSocket);WSACleanup();return -1;}cout << "time: " << RecvBuffer << endl;system("pause");WSACleanup();return 0;}
0 0
- 【网络编程】利用I/O复用模型实现一个时间同步服务器
- 利用I/O复用模型实现一个时间同步服务器
- 利用I/O复用模型实现一个时间同步服务器
- 服务器I/O复用模型实现
- 利用 select 模型,实现一个 I/O 复用模式的服务器
- linux编程---网络编程之复用I/O模型
- Linux网络编程---I/O复用模型之select
- Linux网络编程---I/O复用模型之poll
- Linux网络编程---I/O复用模型之epoll
- 网络编程中I/O复用模型
- 网络编程之I/O复用模型select
- 《网络编程》I/O 模型
- 网络编程 I/O模型
- Linux网络编程之I/O复用循环服务器
- Linux网络编程之I/O复用循环服务器
- Linux网络编程之I/O复用循环服务器
- 网络编程(基于winsocket)-- I/O操作模型介绍--I/0复用模型
- 7种网络编程I/O模型代码实现实例
- 关于ComponentName的使用
- ROC和AUC介绍以及如何计算AUC
- 切换本机默认的jdk
- javascript的setTimeout()用法总结,js的setTimeout()方法
- Linux上gitlab迁移
- 【网络编程】利用I/O复用模型实现一个时间同步服务器
- 站上云端,运用与数据分离,负载均衡布局
- app_zh_CN.properties
- HTTP 1.1与HTTP 1.0的比较
- windows任务栏图标出现(2)如何处理
- qml中关于多个MouseArea之间的事件传递(propagateComposedEvent)
- mongodb 之 特殊集合及索引
- linux 头文件以及库的路径
- Python面试必须要看的15个问题