c++下基于windows socket的单线程服务器客户端程序

今天自己用编写了一个简单的c++服务器客户端程序,注释较详细,在此做个笔记。

windows下socket编程的主要流程可概括如下:初始化ws2_32.dll动态库-->创建套接字-->绑定地址信息-->服务器进行监听/客户端连接服务器-->数据交换-->关闭套接字对象。

服务器端:

  1 #include <Winsock2.h>
  2 #include <Ws2tcpip.h>
  3 #include <iostream>
  4
  5 #pragma comment(lib, "ws2_32.lib") //socket编程需要引用该库
  6
  7 using std::cerr;
  8 using std::cout;
  9 using std::endl;
 10
 11 const char DEFAULT_PORT[] = "4000";
 12 const int RECV_BUF_SIZE = 256;
 13
 14 //服务器
 15 int main() {
 16     WSADATA wsa_data; //WSADATA变量,包含windows socket执行的信息
 17     int i_result = 0; //接收返回值
 18     SOCKET sock_server = INVALID_SOCKET; //创建服务器套接字
 19     SOCKET sock_client = INVALID_SOCKET; //创建客户端套接字
 20     //addrinfo是getaddrinfo()函数用来保存主机地址信息的结构体
 21     addrinfo *result = nullptr; //result是存储地址信息的链表
 22     addrinfo hints;
 23     //初始化winsock动态库(ws2_32.dll),MAKEWORD(2, 2)用于请求使用winsock2.2版本
 24     i_result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
 25     if (i_result != 0) {
 26         cerr << "WSAStartup() function failed: " << i_result << "\n";
 27         system("pause");
 28         return 1;
 29     }
 30     //用0填充内存区域,是ZeroMemory的更安全版本
 31     SecureZeroMemory(&hints, sizeof(addrinfo));
 32     hints.ai_family = AF_INET;
 33     hints.ai_socktype = SOCK_STREAM; //流式套接字用于TCP协议
 34     hints.ai_protocol = IPPROTO_TCP;
 35     hints.ai_flags = AI_PASSIVE; //socket的地址会被用于bind()函数的调用
 36     //确定服务器的地址与端口,将相关信息写入result中
 37     i_result = getaddrinfo(nullptr, DEFAULT_PORT, &hints, &result);
 38     if (i_result != 0) {
 39         cerr << "getaddrinfo() function failed with error: " << WSAGetLastError() << "\n";
 40         WSACleanup();
 41         system("pause");
 42         return 1;
 43     }
 44     //创建服务器套接字
 45     sock_server = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
 46     //套接字创建失败
 47     if (sock_server == INVALID_SOCKET) {
 48         cerr << "socket() function failed with error: " << WSAGetLastError() << "\n";
 49         //将getaddrinfo()函数动态分配的addrinfo中的地址信息释放掉
 50         freeaddrinfo(result);
 51         //释放套接字资源
 52         WSACleanup();
 53         system("pause");
 54         return 1;
 55     }
 56     //将服务器套接字与地址对象绑定,result->ai_addr是结构体的指针
 57     i_result = bind(sock_server, result->ai_addr, static_cast<int>(result->ai_addrlen));
 58     //绑定失败
 59     if (i_result == SOCKET_ERROR) {
 60         cerr << "bind() function failed with error: " << WSAGetLastError() << "\n";
 61         freeaddrinfo(result);
 62         closesocket(sock_server);
 63         WSACleanup();
 64         system("pause");
 65         return 1;
 66     }
 67     freeaddrinfo(result);
 68     cout << "server started successfully..." << endl;
 69     //开始监听
 70     cout << "start listening..." << endl;
 71     i_result = listen(sock_server, SOMAXCONN);
 72     if (i_result == SOCKET_ERROR) {
 73         cerr << "listen() function failed with error: " << WSAGetLastError() << "\n";
 74         closesocket(sock_server);
 75         system("pause");
 76         return 1;
 77     }
 78     //接收客户端请求
 79     sock_client = accept(sock_server, nullptr, nullptr);
 80     if (sock_client == INVALID_SOCKET) {
 81         cerr << "accept() function failed with error: " << WSAGetLastError() << "\n";
 82         closesocket(sock_server);
 83         WSACleanup();
 84         system("pause");
 85         return 1;
 86     }
 87     //接收和发送数据
 88     char recv_buf[RECV_BUF_SIZE];
 89     int send_result = 0;
 90     do {
 91         //不可缺少,若不将内存空间清零会输出乱码,这是因为输送过来的信息未必有256个字节
 92         SecureZeroMemory(recv_buf, RECV_BUF_SIZE);
 93         //标志位一般设置为0
 94         i_result = recv(sock_client, recv_buf, RECV_BUF_SIZE, 0);
 95         if (i_result > 0) {
 96             //exit表示客户端请求断开连接
 97             if (strcmp(recv_buf, "exit") == 0) {
 98                 cout << "client request to close the connection..." << endl;
 99                 break;
100             }
101             //输出接收的字节数
102             cout << "Bytes received: " << i_result << endl;
103             cout << "message received: " << recv_buf << endl;
104             //向客户端发送接收到的数据
105             send_result = send(sock_client, recv_buf, i_result, 0);
106             if (send_result == SOCKET_ERROR) {
107                 cerr << "send() function failed with error: " << WSAGetLastError() << "\n";
108                 closesocket(sock_client);
109                 WSACleanup();
110                 system("pause");
111                 return 1;
112             }
113             cout << "Bytes sent: " << send_result << endl;
114         }
115         //i_result的值为0表示连接已经关闭
116         else if (i_result == 0) {
117             cout << "connection closed..." << endl;
118         }
119         else {
120             cerr << "recv() function failed with error: " << WSAGetLastError() << "\n";
121             closesocket(sock_client);
122             WSACleanup();
123             system("pause");
124             return 1;
125         }
126     } while (i_result > 0); //do...while语句后注意要有分号
127     //shutdown()禁用套接字的接收或发送功能
128     i_result = shutdown(sock_client, SD_SEND);
129     if (i_result == SOCKET_ERROR) {
130         cerr << "shutdown() function failed with error: " << WSAGetLastError() << "\n";
131         closesocket(sock_client);
132         WSACleanup();
133         system("pause");
134         return 1;
135     }
136     //关闭套接字
137     i_result = closesocket(sock_server);
138     WSACleanup();
139     cout << "socket closed..." << endl;
140     system("pause");
141     return 0;
142 }

客户端:

  1 #include <iostream>
  2 #include <WinSock2.h>
  3 #include <Ws2tcpip.h>
  4
  5 #pragma comment(lib, "ws2_32.lib")
  6
  7 using std::cin;
  8 using std::cerr;
  9 using std::cout;
 10 using std::endl;
 11 using std::flush;
 12
 13 const char DEFAULT_PORT[] = "4000";
 14 const int SEND_BUF_SIZE = 256;
 15
 16 //客户端
 17 int main() {
 18     WSADATA wsa_data; //WSADATA变量,包含windows socket执行的信息
 19     int i_result = 0; //接收返回值
 20     SOCKET sock_client = INVALID_SOCKET;
 21     addrinfo *result = nullptr, hints;
 22     //初始化winsock动态库(ws2_32.dll),MAKEWORD(2, 2)用于请求使用winsock2.2版本
 23     i_result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
 24     if (i_result != 0) {
 25         cerr << "WSAStartup() function failed: " << i_result << "\n";
 26         system("pause");
 27         return 1;
 28     }
 29     SecureZeroMemory(&hints, sizeof(hints));
 30     hints.ai_family = AF_UNSPEC;
 31     hints.ai_socktype = SOCK_STREAM;
 32     hints.ai_protocol = IPPROTO_TCP;
 33     //
 34     i_result = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
 35     if (i_result != 0) {
 36         cerr << "getaddrinfo() function failed with error: " << WSAGetLastError() << "\n";
 37         WSACleanup();
 38         system("pause");
 39         return 1;
 40     }
 41     //创建套接字
 42     sock_client = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
 43     if (sock_client == INVALID_SOCKET) {
 44         cerr << "socket() function failed with error: " << WSAGetLastError() << "\n";
 45         WSACleanup();
 46         system("pause");
 47         return 1;
 48     }
 49     //连接服务器
 50     i_result = connect(sock_client, result->ai_addr, result->ai_addrlen);
 51     if (i_result == SOCKET_ERROR) {
 52         cerr << "connect() function failed with error: " << WSAGetLastError() << "\n";
 53         WSACleanup();
 54         system("pause");
 55         return 1;
 56     }
 57     cout << "connect server successfully..." << endl;
 58     //
 59     freeaddrinfo(result);
 60     //
 61     char send_buf[SEND_BUF_SIZE];
 62     int recv_result = 0;
 63     //SecureZeroMemory(send_buf, SEND_BUF_SIZE);
 64     do {
 65         cout << "enter the message that you want to send: " << flush;
 66         cin >> send_buf;
 67         i_result = send(sock_client, send_buf, static_cast<int>(strlen(send_buf)), 0);
 68         if (i_result == SOCKET_ERROR) {
 69             cerr << "send() function failed with error: " << WSAGetLastError() << "\n";
 70             closesocket(sock_client);
 71             WSACleanup();
 72             system("pause");
 73             return 1;
 74         }
 75         cout << "Bytes sent: " << i_result << endl;
 76         //接收服务器返回的数据
 77         recv_result = recv(sock_client, send_buf, SEND_BUF_SIZE, 0);
 78         if (recv_result > 0) {
 79             cout << "feedback from server: " << send_buf << endl;
 80         }
 81         else if (recv_result == 0) {
 82             cout << "connection closed..." << endl;
 83         }
 84         else {
 85             cerr << "recv() function failed with error: " << WSAGetLastError() << "\n";
 86             closesocket(sock_client);
 87             WSACleanup();
 88             system("pause");
 89             return 1;
 90         }
 91     } while (recv_result > 0);
 92     //
 93     i_result = shutdown(sock_client, SD_SEND);
 94     if (i_result == SOCKET_ERROR) {
 95         cerr << "shutdown() function failed with error: " << WSAGetLastError() << "\n";
 96         closesocket(sock_client);
 97         WSACleanup();
 98         system("pause");
 99         return 1;
100     }
101     closesocket(sock_client);
102     WSACleanup();
103     cout << "socket closed..." << endl;
104     system("pause");
105     return 0;
106 }
时间: 2024-12-22 21:49:57

c++下基于windows socket的单线程服务器客户端程序的相关文章

Windows下基于IIS服务的SSL服务器的配置

Windows下基于IIS服务的SSL服务器的配置 实验环境 Windows Server 2008 R1(CA) Windows Server 2008 R2(web服务器) Windows 7 x64(客户端) 3台虚拟机打开桥接模式,保证能够相互ping通 实验原理 CA(根CA)负责为服务器颁发证书使得服务器证书可信. 服务器下载IIS组建,向CA申请一个SSL证书,并且将此证书与本机IP绑定.最后打开SSL服务. 客户端信任CA,因此可以安全地访问服务器网址. 实验步骤 安装证书服务

基于Windows Socket的安全通信(C++实现,附源码)

先了解一下Socket的相关函数原型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 //加载套接字库 int PASCAL FAR WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData); //释放套接字库资源 int PASCAL FAR WSACleanup(void); //创建套接字 SOCKET PASCAL FAR socket (int af,int type,int pr

Windows Socket编程示例-TCP示例程序

前面一部分是介绍,后面有示例 1.网络中进程之间如何通信? 首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们解决了这个问题,网络层的"ip地址"可以唯一标识网络中的主机,而传输层的"协议+端口"可以唯一标识主机中的应用程序(进程).这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互. 使用TCP

Windows 下的最简单的TCP服务器客户端

他们是短连接的,服务器接受客户端之后,马上发送一个消息,发送完以后立即将客户端断开掉,然后继续等待下一个连接. 使用Winsocket2必须要引用到的头文件和需要包含到的链接库文件: #include <WinSock2.h> #pragma comment( lib, "ws2_32.lib" ) 以下代码是Winsocket2的系统初始化和关闭的封装代码. class WinSocketSystem { public: WinSocketSystem() { int i

基于windows平台的linux服务器批量管理可视化工具

产生背景: 由于做服务器运维方面的工作,需要对近千台LINUX服务器进行统一的管理,如同时批量对LINUX服务器执行相关的指令.同时批量对LINUX服务器upload程序包.同时批量对LINUX服务器download程序包.当前世面上也存在一些常见且功能强大的工具,如puppet,dsh,parallel-ssh等,但不得不说,他们的功能太重量了,重量到不得不学习他们的命令以及复杂的用法,且对于刚入LINUX门道的"菜鸟"来说无UI界面纯命令操作也显得太"重"了.故

socket本地模拟服务器+客户端(二)

建立两个py文件,分别打开两个cmd界面,即可进行通信.服务器端运用多进程,连续不断的处理从客户端接收到的数据:客户端通过一个list不断给客户端发送数据. (每个连接都必须创建新线程(或进程)来处理,否则,单线程在处理连接的过程中,无法接受其他客户端的连接.)本例中,多进程其实没有起到作用. 代码以及解释如下: #socket服务器端程序 import socket import time from multiprocessing import Process #多进程和多线程一样的用法 de

Windows消息机制驱动的客户端程序GetMssage()

要从消息队列中取出消息,我们需要调用GetMessage()函数,该函数的原型声明如下: BOOL GetMessage( LPMSG lpMsg,              // address of structure with message HWND hWnd,                 // handle of window UINT wMsgFilterMin,       // first message UINT wMsgFilterMax        // last m

基于C# Socket的Web服务器---静态资源处理

Web服务器是Web资源的宿主,它需要处理用户端浏览器的请求,并指定对应的Web资源返回给用户,这些资源不仅包括HTML文件,JS脚本,JPG图片等,还包括由软件生成的动态内容.为了满足上述需求,一个完整的Web服务器工作流程: 1)   服务器获得浏览器通过TCP/IP连接向服务器发送的http请求数据包. 2)   HTTP请求经过Web服务器的HTTP解析引擎分析得出请求方法.资源地址等信息,然后开始处理. 3)   对于静态请求,则在服务器上查询请求url路径下文件,并返回(如果未找到则

TCP/IP协议学习(五) 基于C# Socket的Web服务器---动态通讯实现

目录 (1).基于Ajax的前端实现 (2).Web服务器后端处理 一个完整的web服务器,不仅需要满足用户端对于图片.文档等资源的需求:还能够对于用户端的动态请求,返回指定程序生成的数据.支持动态请求处理是web服务器的必要组成部分,现有比较成熟的前端动态技术有CGI,ASP/ASP.net, PHP,原生javascript实现的Ajax技术以及基于HTML5的webSocket通讯,它们每一项都涉及很多相关知识,不过归结到核心都是前后端的数据交互,特别是对于后端来说并没有太大区别.作为动态