网站前端设计培训关于网站开发的网站
网站前端设计培训,关于网站开发的网站,wordpress标签使用文章列表,如何做社群营销模式在 Windows 操作系统中#xff0c;原生提供了强大的网络编程支持#xff0c;允许开发者使用 Socket API 进行网络通信#xff0c;通过 Socket API#xff0c;开发者可以创建、连接、发送和接收数据#xff0c;实现网络通信。本文将深入探讨如何通过调用原生网络 API 实现同…在 Windows 操作系统中原生提供了强大的网络编程支持允许开发者使用 Socket API 进行网络通信通过 Socket API开发者可以创建、连接、发送和接收数据实现网络通信。本文将深入探讨如何通过调用原生网络 API 实现同步远程通信并介绍了一个交互式 Socket 类的封装提升了编写交互式服务器的便利性。
1. 交互式套接字类
为了更好地利用原生网络 API我们引入了一个交互式 Socket 类的封装。这个类抽象了底层的网络细节提供了简单而强大的接口使得服务器端的交互式功能更容易实现。我们将详细介绍这个类的设计和使用方法。
MySocket 类是一个 C 套接字类封装了在 Windows 平台上使用原生网络 API 进行同步远程通信的基本功能该类需要使用多字节编码模式服务端与客户端均需要引入此类在项目头文件中均需要新建MySocket.hpp文件。
完整代码如下所示
#pragma once
#include WinSock2.h
#pragma comment(lib, ws2_32.lib)class MySocket
{
protected:SOCKET m_hSocket;
public:// 获取对端Socket用户IP端口等BOOL GetPeerName(char* rSocketAddress, UINT rSocketPort){sockaddr_in name { AF_INET };int lenname sizeof(name);if (getpeername(m_hSocket, (sockaddr*)name, lenname) 0)return false;strcpy(rSocketAddress, inet_ntoa(name.sin_addr));rSocketPort htons(name.sin_port);return true;}// 获取本机Socket用户IP端口等BOOL GetSockName(char* rSocketAddress, UINT rSocketPort){sockaddr_in name { AF_INET };int lenname sizeof(name);if (getsockname(m_hSocket, (sockaddr*)name, lenname) 0)return false;strcpy(rSocketAddress, inet_ntoa(name.sin_addr));rSocketPort htons(name.sin_port);return true;}// 获取当前用户SocketIDBOOL GetSocketID(){return m_hSocket;}// 创建套接字BOOL Create(UINT nSocketPort 0, int nSockType SOCK_STREAM, LPCTSTR lpszSocketAddress NULL){// 创建套接字m_hSocket socket(AF_INET, nSockType, 0);if (m_hSocket INVALID_SOCKET)return false;// 设置IP地址和端口sockaddr_in sa { AF_INET };sa.sin_port htons(nSocketPort);if (lpszSocketAddress)sa.sin_addr.s_addr inet_addr(lpszSocketAddress);// 绑定套接字和IP地址端口return !bind(m_hSocket, (sockaddr*)sa, sizeof(sa));}// 接受客户请求BOOL Accept(MySocket rConnectedSock, LPSTR szIp NULL, UINT* nPort NULL){sockaddr_in sa { AF_INET };int nLen sizeof(sa);rConnectedSock.m_hSocket accept(this-m_hSocket, (sockaddr*)sa, nLen);if (rConnectedSock.m_hSocket INVALID_SOCKET)return false;if (szIp)strcpy(szIp, inet_ntoa(sa.sin_addr));if (nPort)*nPort htons(sa.sin_port);return true;}// 连接服务端BOOL Connection(LPCSTR lpszHostAddress, UINT nPort){sockaddr_in sa { AF_INET };sa.sin_port htons(nPort);sa.sin_addr.s_addr inet_addr(lpszHostAddress);return !connect(m_hSocket, (sockaddr*)sa, sizeof(sa));}// 侦听BOOL Listen(int nConnectionBacklog 5){return !listen(m_hSocket, nConnectionBacklog);}// 逐条发送int Send(const void* lpBuf, int nBufLen, int nFlags 0){return send(m_hSocket, (LPCSTR)lpBuf, nBufLen, nFlags);}// 发送整个缓冲区int SendTo(const void* lpBuf, int nBufLen, UINT nHostPort, LPCSTR lpszHostAddress NULL,int nFlags 0){sockaddr_in to { AF_INET };to.sin_port htons(nHostPort);to.sin_addr.s_addr inet_addr(lpszHostAddress);return sendto(m_hSocket, (LPCSTR)lpBuf, nBufLen, nFlags, (sockaddr*)to, sizeof(to));}// 逐条接收int Receive(void* lpBuf, int nBufLen, int nFlags 0){return recv(m_hSocket, (LPTSTR)lpBuf, nBufLen, nFlags);}// 接收整个缓冲区int ReceiveFrom(void* lpBuf, int nBufLen, char* rSocketAddress, UINT rSocketPort, int nFlags 0){sockaddr_in from { AF_INET };int lenFrom sizeof(from);int n recvfrom(m_hSocket, (LPSTR)lpBuf, nBufLen, nFlags, (sockaddr*)from, lenFrom);strcpy(rSocketAddress, inet_ntoa(from.sin_addr));rSocketPort htons(from.sin_port);return n;}// 关闭套接字void Close(){closesocket(m_hSocket);m_hSocket INVALID_SOCKET;}MySocket(){WSADATA wsaData;WSAStartup(0x0202, wsaData);m_hSocket INVALID_SOCKET;}~MySocket(){Close();}
};以下是对该类的概括
类名MySocket功能提供了基本的网络通信功能包括创建套接字、获取对端和本机的信息、接受客户端连接、连接服务端、监听连接请求、发送和接收数据。成员变量 SOCKET m_hSocket套接字句柄用于标识一个套接字。 成员函数 Create创建套接字并可指定类型、本地端口和地址。Accept接受客户请求返回连接的套接字。Connection连接到服务端。Listen开始监听连接请求。Send逐条发送数据。SendTo发送整个缓冲区到指定地址。Receive逐条接收数据。ReceiveFrom接收整个缓冲区并获取发送端地址和端口。Close关闭套接字。 初始化和清理 构造函数 MySocket初始化 Winsock 库和套接字句柄。析构函数 ~MySocket关闭套接字。 使用注意事项 适用于简单的同步网络通信场景。
该类提供了一些基本的网络编程功能适合用于创建简单的服务器端和客户端。需注意这是一个同步实现的套接字类适用于一些较为简单的网络通信需求。
2. 实现简单的通信
通过具体的代码示例我们将演示如何使用交互式 Socket 类在 Windows 操作系统上实现同步远程通信。代码将包括服务器端和客户端的实现以及它们之间的交互过程。通过这些示例读者将更好地理解如何在实际项目中应用这些概念。
2.1 服务端流程
如下代码是一个简单的服务端程序通过 MySocket 类建立基于 TCP 协议的服务器通过sock.Create()创建套接字然后通过sock.Accept()接收套接字当有新的套接字连入时自动调用_beginthread()函数开启一个子线程维持套接字的运行每一个子线程内部则都由ClientPro()函数来实现交互。
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS#include iostream
#include process.h
#include MySocket.hppusing namespace std;void ClientPro(void* ptr)
{// 初始化MySocket* pSock (MySocket*)ptr;MySocket server_socket *pSock;server_socket.Send((const char *)Welcome to LyServer, 19);// 获取客户端信息char sIp[20];UINT nPort;server_socket.GetPeerName(sIp, nPort);while (true){char szBuffer[4096] { 0 };// 接收客户返回消息int ref server_socket.Receive(szBuffer, sizeof(szBuffer));if (ref 0){std::cout 客户: sIp : nPort [已断开] std::endl;break;}std::cout 地址: sIp : nPort 接收命令: szBuffer std::endl;// 选择不同的命令if (strcmp(szBuffer, list\n) 0){std::cout 输出文件 std::endl;}else if (strcmp(szBuffer, download\n) 0){std::cout 下载文件 std::endl;}else if (strcmp(szBuffer, upload\n) 0){std::cout 上传文件 std::endl;}// 返回给客户端server_socket.Send((char*)ok, 2);}
}int main(int argc, char *argv[])
{MySocket sock;if (!sock.Create(8233, SOCK_STREAM, 127.0.0.1)){return -1;}// 获取本机信息char sSevIp[20];UINT nSevPort;sock.GetSockName(sSevIp, nSevPort);std::cout 服务端: sSevIp : nSevPort 服务器启动成功 std::endl;sock.Listen(5);// 获取客户端信息char sIp[20];UINT nPort;MySocket ptr;while (true){// 当有新用户进来自动创建一个线程来维持会话sock.Accept(ptr, sIp, nPort);std::cout 客户: sIp : nPort [已登录] std::endl;// 多线程_beginthread(ClientPro, 0, ptr);}return 0;
}以下是对该代码的概括
功能实现一个简单的基于 TCP 的服务器监听指定端口8233接受客户端连接创建一个线程处理每个客户端的会话。主要函数和过程 ClientPro 函数处理每个客户端的会话。向客户端发送欢迎消息接收客户端发送的命令根据不同的命令执行相应的操作并向客户端发送响应。该函数通过多线程在后台运行使得服务器能够同时处理多个客户端。main 函数在主线程中创建 MySocket 类实例 sock并调用 Create 函数创建服务器套接字。然后通过 Listen 函数监听客户端连接。在循环中通过 Accept 函数接受客户端连接并为每个客户端创建一个新线程用于处理客户端的会话。 通信协议客户端和服务器之间通过简单的文本协议进行通信。客户端发送不同的命令“list”、“download”、“upload”服务器接收命令并执行相应的操作然后向客户端发送响应“ok”。线程创建使用 _beginthread 函数在每个新连接上创建一个线程用于处理该客户端的会话。
2.2 客户端流程
如下代码是一个简单的客户端程序通过 MySocket 类实现与服务端的基于 TCP 协议的通信通过sock.Connection()建立套接字链接通过sock.Receive()接收数据通过sock.Send()发送数据其运行原理与原生套接字写法保持一致。
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include iostream
#include MySocket.hppusing namespace std;int main(int argc, char* argv[])
{MySocket sock;if (!sock.Create(0, SOCK_STREAM)){return -1;}// 获取本机信息char sClientIp[20];UINT nClientPort;sock.GetSockName(sClientIp, nClientPort);std::cout 服务端: sClientIp : nClientPort 服务器启动成功 std::endl;if (!sock.Connection(127.0.0.1, 8233)){cout 连接服务器失败 GetLastError() endl;return -1;}char szBuffer[4096] { 0 };int ref sock.Receive(szBuffer, sizeof(szBuffer));szBuffer[ref] 0;std::cout 服务端回应: szBuffer std::endl;while (true){// 循环接受输入input:memset(szBuffer, 0, 4096);std::cout Input CMD ;// 接收输入命令int inputLine 0;while ((szBuffer[inputLine] getchar()) ! \n);if (strlen(szBuffer) 1)goto input;// 发送数据sock.Send(szBuffer, 4096, 0);// 接收回显memset(szBuffer, 0, 4096);sock.Receive(szBuffer, 4096, 0);std::cout 服务端回显: szBuffer std::endl;}sock.Close();return 0;
}以下是对该代码的概括
功能实现一个基于 TCP 的客户端连接到指定 IP 地址和端口127.0.0.1:8233与服务器建立连接后可以输入命令并发送到服务器接收并显示服务器的回显。主要函数和过程 main 函数在主线程中创建 MySocket 类实例 sock并调用 Create 函数创建客户端套接字。然后通过 Connection 函数连接到服务器。接着通过 Receive 函数接收服务器发送的欢迎消息并显示在控制台。在一个无限循环中通过标准输入接收用户输入的命令将命令发送到服务器然后接收并显示服务器的回显。 通信协议客户端和服务器之间通过简单的文本协议进行通信。客户端发送用户输入的命令服务器执行命令并将结果回显给客户端。输入循环通过一个无限循环不断接收用户输入的命令并发送到服务器。如果用户输入空命令程序会跳转回 input 标签重新接收输入。错误处理在连接服务器失败时通过 GetLastError() 输出详细错误信息。关闭套接字在程序结束时通过 sock.Close() 关闭套接字。
依次运行服务端和客户端然后当客户端连接成功后此时的服务端即可收到连接请求此时客户端可以执行各类简单的命令如下图所示 3.实现登录服务器
上述代码只是一个简单的演示案例用来演示如何使用套接字编写交互程序如下我们将继续完善这段代码实现一个简单的带有登录功能的登录服务器程序使用户可以在执行命令前具备简单的登录认证功能。
3.1 服务端流程
如下代码是一个简单的基于 Windows 的多线程服务器程序通过 MySocket 类实现与客户端的基于 TCP 协议的通信在交互模式下用户可输入多种命令登录登出以及登陆后的命令执行功能。
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS#include iostream
#include process.h
#include vector
#include MySocket.hppusing namespace std;// 登录状态记录
typedef struct
{char UserName[32];int SocketID;
}loginPool;// ------------------------------------------------------------------------
// 用户登录验证代码部分std::vectorloginPool login_pool_vect;// 检查用户ID是否存在与容器内,如果存在则返回用户名
bool is_login(std::vectorloginPool ptr, int socket_id)
{for (int x 0; x ptr.size(); x){if (ptr[x].SocketID socket_id){return true;}}return false;
}// 用户登录验证
bool login(char *username, char *password, int socket_id)
{if ((strcmp(username, lyshark) 0) (strcmp(password, 123123) 0)){// 如果在则增加一个socket登录标志loginPool pool_ptr;pool_ptr.SocketID socket_id;strcpy(pool_ptr.UserName, lyshark);login_pool_vect.push_back(pool_ptr);return true;}else if ((strcmp(username, admin) 0) (strcmp(password, 123456) 0)){// 如果在则增加一个socket登录标志loginPool pool_ptr;pool_ptr.SocketID socket_id;strcpy(pool_ptr.UserName, lyshark);login_pool_vect.push_back(pool_ptr);return true;}return false;
}// 根据传入ID从容器内弹出一个节点
bool logout(std::vectorloginPool ptr, int socket_id)
{for (vectorloginPool::iterator it ptr.begin(); it ! ptr.end(); it){if (it-SocketID socket_id){// 弹出指定结构体ptr.erase(it);return true;}}return false;
}// ------------------------------------------------------------------------
// 响应客户端的子线程(主要功能实现部分)
void ClientPro(void* ptr)
{// 初始化MySocket* pSock (MySocket*)ptr;MySocket server_socket *pSock;server_socket.Send((const char *)Welcome to LyShark Mini Server, 31);// 获取客户端信息char sIp[20];UINT nPort;server_socket.GetPeerName(sIp, nPort);while (true){char szBuffer[4096] { 0 };int sid pSock-GetSocketID();int ref server_socket.Receive(szBuffer, sizeof(szBuffer));if (ref 0){logout(login_pool_vect, sid);std::cout 客户: sIp : nPort [已断开] std::endl;break;}std::cout 地址: sIp : nPort 接收命令: szBuffer std::endl;// 用户登录if (strcmp(szBuffer, login\n) 0){char recv_username[32] { 0 };char recv_password[32] { 0 };// 接收用户名和密码pSock-Receive(recv_username, 32, 0);pSock-Receive(recv_password, 32, 0);// 验证登录状态bool login_flag login(recv_username, recv_password, sid);if (login_flag TRUE){std::cout 用户: recv_username 已登录 std::endl;pSock-Send(已登录, sizeof(已登录), 0);}else{pSock-Send(账号或密码错误, sizeof(账号或密码错误), 0);}}// 用户登出else if (strcmp(szBuffer, logout\n) 0){// 验证是否登录成功int login_flag is_login(login_pool_vect, sid);if (login_flag TRUE){std::cout 用户已登出 std::endl;logout(login_pool_vect, sid);pSock-Send(用户已登出, sizeof(用户已登出), 0);}else{std::cout 请先登录 std::endl;pSock-Send(请先登录, sizeof(请先登录), 0);}}// 遍历本机文件else if (strcmp(szBuffer, list\n) 0){// 验证是否登录成功int login_flag is_login(login_pool_vect, sid);if (login_flag TRUE){std::cout 用户已登录,输出本机文件 std::endl;pSock-Send(认证通过, sizeof(认证通过), 0);// 循环输出数据包for (int x 0; x 10; x){char sz[1024] { 0 };sprintf(sz, count - %d, x);pSock-Send(sz, sizeof(sz), 0);}}else{std::cout 请先登录 std::endl;pSock-Send(请先登录, sizeof(请先登录), 0);}}}
}int main(int argc, char *argv[])
{MySocket sock;if (!sock.Create(8233, SOCK_STREAM, 127.0.0.1)){return -1;}// 获取本机信息char sSevIp[20];UINT nSevPort;sock.GetSockName(sSevIp, nSevPort);std::cout 服务端: sSevIp : nSevPort 服务器启动成功 std::endl;sock.Listen(5);// 获取客户端信息char sIp[20];UINT nPort;MySocket ptr;while (true){sock.Accept(ptr, sIp, nPort);std::cout 客户: sIp : nPort [已登录] std::endl;// 多线程_beginthread(ClientPro, 0, ptr);}return 0;
}以下是对该代码的概括
功能 通过 MySocket 类实现基于 TCP 协议的多线程服务器可以处理多个客户端的连接。实现了用户登录验证功能支持用户登录、登出和查看本机文件列表的操作。 主要结构和功能 登录状态记录结构体 (loginPool)记录用户登录状态包括用户名和套接字 ID。用户登录验证相关函数 is_login检查指定套接字 ID 是否已登录。login验证用户名和密码如果验证通过则将用户信息加入登录池。logout根据套接字 ID 从登录池中移除用户。 子线程主要处理函数 ClientPro 初始化后发送欢迎消息给客户端。接收客户端命令处理用户登录、登出和查看本机文件列表的请求。针对不同的命令进行相应的处理和回复。 主线程 main 创建服务器套接字并通过 Create 函数创建服务器套接字。获取本机信息包括 IP 地址和端口并显示在控制台。通过 Listen 函数监听客户端连接。接受客户端连接创建子线程处理每个客户端连接。 通信协议服务器与客户端之间通过简单的文本协议进行通信支持用户登录、登出和查看本机文件列表的操作。多线程处理通过 _beginthread 创建子线程处理每个客户端的连接实现了多客户端并发处理。用户登录验证支持用户登录验证功能通过用户名和密码验证用户身份记录登录状态处理用户登录、登出的请求。
3.2 客户端流程
如下代码是一个基于 Windows 的客户端程序通过 MySocket 类实现与服务器的基于 TCP 协议的通信。
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include iostream
#include MySocket.hppusing namespace std;int main(int argc, char* argv[])
{MySocket sock;if (!sock.Create(0, SOCK_STREAM)){return -1;}// 获取本机信息char sClientIp[20];UINT nClientPort;sock.GetSockName(sClientIp, nClientPort);if (!sock.Connection(127.0.0.1, 8233)){cout 连接服务器失败 GetLastError() endl;return -1;}char szBuffer[4096] { 0 };int ref sock.Receive(szBuffer, sizeof(szBuffer));szBuffer[ref] 0;std::cout 服务端回应: szBuffer std::endl;while (true){input:memset(szBuffer, 0, 4096);std::cout CMD ;// 发送命令int inputLine 0;while ((szBuffer[inputLine] getchar()) ! \n);if (strlen(szBuffer) 1)goto input;// 执行登录if (strcmp(szBuffer, login\n) 0){// 发送命令sock.Send(szBuffer, 4096, 0);char input_username[32] { 0 };char input_password[32] { 0 };// 发送用户名printf(用户名: );scanf(%s, input_username);sock.Send(input_username, 32, 0);// 发送密码printf(密码: );scanf(%s, input_password);sock.Send(input_password, 32, 0);// 获取登录状态char recv_message[64] { 0 };sock.Receive(recv_message, 64, 0);std::cout recv_message std::endl;}// 登出用户else if (strcmp(szBuffer, logout\n) 0){// 发送命令sock.Send(szBuffer, 4096, 0);// 获取返回消息char recv_message[64] { 0 };sock.Receive(recv_message, 64, 0);std::cout recv_message std::endl;}// 遍历本机文件else if (strcmp(szBuffer, list\n) 0){// 发送命令sock.Send(szBuffer, 4096, 0);// 获取返回消息char recv_message[64] { 0 };sock.Receive(recv_message, 64, 0);std::cout recv_message std::endl;if (strcmp(recv_message, 请先登录) 0){goto input;}// 循环接收数据包for (int x 0; x 10; x){char sz[1024] { 0 };sock.Receive(sz, 1024, 0);std::cout sz std::endl;}}}sock.Close();return 0;
}以下是对该代码的概括
功能 通过 MySocket 类实现基于 TCP 协议的客户端可以与服务器进行通信。支持用户通过命令行输入与服务器进行简单的交互包括登录、登出和查看本机文件列表的操作。 主要结构和功能 用户交互循环 使用一个循环通过命令行输入命令将命令发送给服务器并根据服务器的回应进行相应的操作。支持登录、登出和查看本机文件列表的操作。 命令处理 对用户输入的不同命令通过 sock.Send 将命令发送给服务器并通过 sock.Receive 接收服务器的回应。具体命令包括登录、登出和查看本机文件列表。 登录交互 当用户输入 “login” 命令时程序会提示用户输入用户名和密码并将输入的用户名和密码发送给服务器进行登录验证。接收服务器的回应输出相应的登录状态信息。 登出交互 当用户输入 “logout” 命令时程序向服务器发送登出命令接收服务器的回应并输出相应的信息。 查看本机文件列表交互 当用户输入 “list” 命令时程序向服务器发送查看本机文件列表的命令接收服务器的回应并输出相应的信息。如果用户未登录则输出 “请先登录” 提示并继续等待用户输入。 通信协议客户端与服务器之间通过简单的文本协议进行通信服务器回应的信息通过控制台输出。
与之前的程序不同这段代码增加了简单的用户认证模式当用户直接执行命令时则会提示客户端请先登录无法执行命令 此时通过login命令并输入用户名lyshark密码123123则会提示已登录此时就可以执行任意的命令参数了如下图所示当结束时还需要使用logout退出当前会话
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/90191.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!