发两篇文章水一水,拿点积分
非计算机专业,只是有需要临时学习的,大佬轻喷
头文件"TCPServer.h"
///
//
// TCP通信,服务端
// ------ design by karaoit
///
#pragma once
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")
#define IP "127.0.0.1"
#define Htons 65432
//宏定义
#ifndef _TCPSERVER_H
#define _TCPSERVER_H
class TCPServer {
/**
@brief:构造函数,每次创建类的新对象时执行
@param:无
@note:无
@retval:无
*/
public: TCPServer();
/**
@brief:析构函数,每次删除所创建的对象时执行
@param:无
@note:无
@retval:无
*/
public: ~TCPServer();
private: WSADATA wsaData; //存储winsock初始化数据
private: SOCKET serverSocket, clientSocket; //套接字
private: struct sockaddr_in serverAddr, clientAddr; //定义两个结构体,用于存储服务器和客户端的地址信息
private: int addrLen = sizeof(clientAddr); //定义地址结构的长度
private: char buffer[1024] = { 0 }; //用于存储接收和发送的数据
/**
@brief:构建TCP通信服务端,初始化TCP配置
@param:无
@note:无
@retval:0 表示成功构建服务端, -1表示异常退出
*/
public: int TCPServerInit(void);
/**
@brief:向客户端发送信息
@param:无
@note:测试用代码
@retval:无
*/
public: void SendInfo(void);
/**
@brief:接收来自客户端的信息
@param:无
@note:测试用代码
@retval:无
*/
public: void ReceiveInfo(void);
/**
@brief:关闭服务端
@param:无
@note:无
@retval:无
*/
public: void TCPServerCloss(void);
// 关闭套接字
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
};
#endif // !_TCPSERVER_H
代码详解:
需要引入的库:
-
winsock2.h
和ws2tcpip.h
是Windows socket API的必要头文件。iostream
和string
用于输入输出和字符串操作。
#pragma comment(lib, "ws2_32.lib")
指示链接器链接Winsock库。
宏定义:
#define IP "127.0.0.1"
回环地址,指向本机,若想要与其他主机通信需改为对应IP地址
#define Htons 65432
端口号,服务端与客户端端口号需保持一致
源文件"TCPServer.cpp"
///
//
// TCP通信,服务端
// ------ design by Karaoit
///
#include "TCPServer.h"
#include <iostream>
TCPServer::TCPServer() {
std::cout << "TCPServer Create" << std::endl;
}
TCPServer::~TCPServer() {
std::cout << "TCPServer Delete" << std::endl;
}
int TCPServer::TCPServerInit(void) {
// 初始化Winsock
WSAStartup(MAKEWORD(2, 2), &wsaData);
// 创建套接字
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "Unable to create socket" << std::endl;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(65432);
// 绑定套接字
bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
// 开始监听
listen(serverSocket, 3);
std::cout << "服务器正在监听:65432..." << std::endl;
// 接受连接
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &addrLen);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Accept failed" << std::endl;
return -1;
}
return 0;
}
void TCPServer::SendInfo(void) {
std::string response;
std::cout << "请输入要发送的消息: ";
std::getline(std::cin, response);
send(clientSocket, response.c_str(), response.length(), 0);
}
void TCPServer::ReceiveInfo(void) {
int valread = recv(clientSocket, buffer, sizeof(buffer), 0);
if (valread > 0) {
std::cout << "收到消息: " << buffer << std::endl;
// 清空缓冲区
memset(buffer, 0, sizeof(buffer));
}
}
void TCPServer::SendInfo(std::string message) {
std::cout << "发送消息: " << message << std::endl;
send(clientSocket, message.c_str(), message.length(), 0);
}
void TCPServer::SendInfo(int value) {
std::string message;
message = std::to_string(value);
std::cout << "发送数据:" << value << std::endl;
send(clientSocket, message.c_str(), message.length(), 0);
}
void TCPServer::TCPServerCloss(void) {
// 关闭套接字
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
}
代码详解:
TCPServer::TCPServerInit(void)
WSAStartup(MAKEWORD(2, 2), &wsaData);
WSAStartup
函数用于初始化Winsock库,这是Windows下进行网络编程的基础库。MAKEWORD(2, 2)
指定使用的Winsock版本是2.2
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
socket
函数用于创建一个套接字(socket)。AF_INET
表示使用IPv4地址,SOCK_STREAM
表示使用TCP协议。创建成功后,serverSocket
变量将被赋值为新创建的套接字句柄
bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
bind
函数将创建的套接字与指定的地址结构绑定,这样网络上的数据包就能正确转发到该套接字。
listen(serverSocket, 3);
listen
函数让套接字进入监听状态,等待客户端的连接请求。这里的第一个参数是要监听的套接字,第二个参数指定了允许的待处理连接的最大数量
TCPServer::SendInfo(void)
send(clientSocket, response.c_str(), response.length(), 0);
send
函数用于向已连接的客户端发送消息。参数说明:
clientSocket
是之前接受连接时获得的套接字句柄,指定了要发送数据的目标客户端response.c_str()
返回指向response
字符串数据的指针,将其转换为C风格字符串(const char*
类型),这是send
函数所需的格式response.length()
获取消息的长度- 最后一个参数
0
表示使用默认的发送选项
TCPServer::ReceiveInfo(void)
int valread = recv(clientSocket, buffer, sizeof(buffer), 0);
clientSocket
是当前与客户端连接的套接字句柄。buffer
是一个字符数组(通常是一个char
类型的数组)用于存储接收到的数据。sizeof(buffer)
指定了要读取的最大字节数,也就是buffer
的大小。- 最后一个参数
0
表示使用默认的接收选项。
memset(buffer, 0, sizeof(buffer));
使用 memset
函数清空 buffer
,将其所有字节设为 0
。这样做是为了在下次接收消息前确保 buffer
是空的,避免输出重复的旧数据。
主函数
#include "TCPServer.h"
int main() {
TCPServer tcp;
while (tcp.TCPServerInit() != 0);
while (true) {
tcp.ReceiveInfo();
tcp.SendInfo();
}
tcp.TCPServerCloss();
tcp.~TCPServer();
return 0;
}