1.开发软件:VS2017
2.开发语言:C++
3.操作系统:Windows10
3.使用技术:Socket、MFC
基于MFC的客户端效果
控制台客户端效果
①客户端与服务端建立连接
②客户端向服务端发送注册、登录的数据信息。
③服务端验证客户端的信息,向客户端发送是否验证成功的消息。
1.创建控制台应用程序:ServerSocket_CSDN
2.服务端程序代码&注释
#define _WINSOCK_DEPRECATED_NO_WARNINGS //防止报错
#include
#include
using namespace std;
#pragma comment(lib,"ws2_32.lib")
int main()
{
/*初始化启动信息*/
WORD sockVersion = MAKEWORD(2, 2);//调用2.2版本的socket
WSADATA wsaData; //WSA(Windows Sockets Asynchronous)异步套接字
//将指定版本的socket与该应用程序绑定
if (WSAStartup(sockVersion, &wsaData) != 0) //返回为0则表示初始化成功
return 0;
/*创建服务器Socket*/
//AF_INET,使用IPV4通信;SOCK_STREAM,使用流式套接字;IPPROTO_TCP,采用TCP协议
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) //如果创建失败,则输出错误
{
cout << "socket error:" << WSAGetLastError() << endl;
WSACleanup(); //中止Windows Sockets DLL的使用;与上面WSAStartup()配套使用
return 0;
}
//创建服务器Socket套接字成功后
/*sockaddr_in是一个结构体,需要指定 协议族 + IP地址 + 端口号*/
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET; //指定协议族,AF_INET<->IPV4;AF_INET6<->IPV6
serverAddr.sin_addr.S_un.S_addr = INADDR_ANY; //指定IP地址
serverAddr.sin_port = htons(8888); //指定端口号
//Socket绑定地址,第二个参数注意需要使用强制转换
if (bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
cout << "Bind Error!" << endl;
closesocket(serverSocket);
WSACleanup();
return 0;
}
//建立监听客户端请求的信号,设置最多有5个客户端
if (listen(serverSocket, 5) == SOCKET_ERROR)//如果建立失败
{
cout << "Listen Error !" << endl;
closesocket(serverSocket); //关闭Socket套接字
WSACleanup();
return 0;
}
cout << "正在监听..." << endl;
//开始不断处理各个客户端请求
while (true)
{
SOCKET clientSocket = INVALID_SOCKET; //初始化一个客户端socket
sockaddr_in clientAddr; //客户端的地址结构
int iAddrLength = sizeof(clientAddr); //求出该结构的长度
cout << "等待登录..." << endl;
//接收客户端的连接请求。第一个参数为服务端Socket,第二个参数用来接收从客户端传来的地址,第三个参数为地址结构的长度
clientSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &iAddrLength);//accept为阻塞函数
if (clientSocket == INVALID_SOCKET) //如果接收失败
{
cout << "Accept Error !" << WSAGetLastError() << endl;
closesocket(serverSocket);
WSACleanup();
return 0;
}
//inet_ntoa将网络地址转换为字符输出
cout << "客户端地址:" << inet_ntoa(clientAddr.sin_addr) << endl;
//开始不断接收该客户端数据
char buffFromClient[1024]; //用于接收客户端传来的数据
while(true)
{
memset(buffFromClient, 0, sizeof(buffFromClient));
//recv也为阻塞函数,只有客户端发送数据过来后,程序才会往下继续走
int iLenOfRecvData = recv(clientSocket, buffFromClient, sizeof(buffFromClient), 0);
if (iLenOfRecvData > 0) //如果接收的数据不为空
{
cout << buffFromClient << endl;
}
else
{
cout << "服务器断开,无接收..." << endl;
break;
}
char sendToClientBuff[1024] = "服务端收到啦!";
send(clientSocket, sendToClientBuff, sizeof(sendToClientBuff), 0);
}
closesocket(clientSocket);//关闭与该客户端的套接字
}
closesocket(serverSocket);//关闭服务器套接字
WSACleanup();
}
1.新建MFC对话框程序:ClientSocket_CSDN
2.UI设计,添加Button控件
3.实现点击Button控件向服务端发送消息的函数
①在.h文件中添加需要的头文件、库,定义一个全局变量:m_clientSocket。
②修改项目属性,将SDL检查设置为:否,用于防止报错。
③编写OnBnClickedButton1()函数
void CClientSocketCSDNDlg::OnBnClickedButton1()
{
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;//WSA(Windows Sockets Asynchronous)异步套接字
if (WSAStartup(sockVersion, &wsaData) != 0)
return;
m_clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_clientSocket == INVALID_SOCKET)
{
MessageBox("Invalid Socket!", "错误", MB_ICONERROR);
return;
}
//建立一个客户端地址
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8888);
serAddr.sin_addr.S_un.S_addr = inet_addr("127.1.0.1");
//客户端向服务端请求连接
if (connect(m_clientSocket, (sockaddr*)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{
MessageBox("Connect Error!!", "错误", MB_ICONERROR);
closesocket(m_clientSocket);
return;
}
//与服务端连接成功,开发发送消息
char sendToServerBuff[1024] = "服务端,我来啦~";
send(m_clientSocket, *(&sendToServerBuff), sizeof(sendToServerBuff), 0);
//接收服务端返回的消息
char buffFromServer[1024];
int recvDataLen = recv(m_clientSocket, buffFromServer, sizeof(buffFromServer), 0);
if (recvDataLen > 0)
{
MessageBox(buffFromServer);
}
closesocket(m_clientSocket);
WSACleanup();
}
见我另一篇博客:(详细源码)C++ socket 传输不同类型数据的四种方式_abcdefzzzz的博客-CSDN博客
1.添加StudentInfo类
2.服务端目录结构如下:
3.类对象的.h程序代码
//StudentInfo.h文件如下,.cpp文件自行实现
#pragma once
#include
using namespace std;
class StudentInfo
{
private:
int m_iId;
string m_strName;
bool m_bSex;
public:
StudentInfo();
~StudentInfo();
int GetId();
string GetName();
bool GetSex();
void SetId(int iId);
void SetName(string strName);
void SetSex(bool bSex);
};
4.实现传输类对象的程序代码
#define _WINSOCK_DEPRECATED_NO_WARNINGS //防止报错
#include
#include
#include
#include "StudentInfo.h"
using namespace std;
#pragma comment(lib,"ws2_32.lib")
struct Student
{
int iId;
string strName;
bool bSex;
};
int main()
{
/*初始化启动信息*/
WORD sockVersion = MAKEWORD(2, 2);//调用2.2版本的socket
WSADATA wsaData; //WSA(Windows Sockets Asynchronous)异步套接字
//将指定版本的socket与该应用程序绑定
if (WSAStartup(sockVersion, &wsaData) != 0) //返回为0则表示初始化成功
return 0;
/*创建服务器Socket*/
//AF_INET,使用IPV4通信;SOCK_STREAM,使用流式套接字;IPPROTO_TCP,采用TCP协议
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) //如果创建失败,则输出错误
{
cout << "socket error:" << WSAGetLastError() << endl;
WSACleanup(); //中止Windows Sockets DLL的使用;与上面WSAStartup()配套使用
return 0;
}
//创建服务器Socket套接字成功后
/*sockaddr_in是一个结构体,需要指定 协议族 + IP地址 + 端口号*/
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET; //指定协议族,AF_INET<->IPV4;AF_INET6<->IPV6
serverAddr.sin_addr.S_un.S_addr = INADDR_ANY; //指定IP地址
serverAddr.sin_port = htons(8888); //指定端口号
//Socket绑定地址,第二个参数注意需要使用强制转换
if (bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
cout << "Bind Error!" << endl;
closesocket(serverSocket);
WSACleanup();
return 0;
}
//建立监听客户端请求的信号,设置最多有5个客户端
if (listen(serverSocket, 5) == SOCKET_ERROR)//如果建立失败
{
cout << "Listen Error !" << endl;
closesocket(serverSocket); //关闭Socket套接字
WSACleanup();
return 0;
}
cout << "正在监听..." << endl;
//开始不断处理各个客户端请求
StudentInfo stuInfo;
while (true)
{
SOCKET clientSocket = INVALID_SOCKET; //初始化一个客户端socket
sockaddr_in clientAddr; //客户端的地址结构
int iAddrLength = sizeof(clientAddr); //求出该结构的长度
cout << "等待登录..." << endl;
//接收客户端的连接请求。第一个参数为服务端Socket,第二个参数用来接收从客户端传来的地址,第三个参数为地址结构的长度
clientSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &iAddrLength);//accept为阻塞函数
if (clientSocket == INVALID_SOCKET) //如果接收失败
{
cout << "Accept Error !" << WSAGetLastError() << endl;
closesocket(serverSocket);
WSACleanup();
return 0;
}
//inet_ntoa将网络地址转换为字符输出
cout << "客户端地址:" << inet_ntoa(clientAddr.sin_addr) << endl;
//开始不断接收该客户端数据
char buffFromClient[1024]; //用于接收客户端传来的数据
while(true)
{
memset(buffFromClient, 0, sizeof(buffFromClient));
//recv也为阻塞函数,只有客户端发送数据过来后,程序才会往下继续走
int iLenOfRecvData = -1;
//传输类对象数据
iLenOfRecvData = recv(clientSocket, (char*)&stuInfo, sizeof(StudentInfo), 0);
if (iLenOfRecvData > 0) //如果接收的数据不为空
{
cout << stuInfo.GetId() << endl;
cout << stuInfo.GetName() << endl;
cout << stuInfo.GetSex() << endl;
}
else
{
cout << "服务器断开,无接收..." << endl;
break;
}
char sendToClientBuff[1024] = "服务端收到啦!";
send(clientSocket, sendToClientBuff, sizeof(sendToClientBuff), 0);
}
closesocket(clientSocket);//关闭与该客户端的套接字
}
closesocket(serverSocket);//关闭服务器套接字
WSACleanup();
}
1.添加StudentInfo类(同服务端)
2.客户端目录结构如下:
3.类对象的程序代码同服务端。
4.编写OnBnClickedButton1函数,实现传输类对象的程序代码
void CClientSocketCSDNDlg::OnBnClickedButton1()
{
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;//WSA(Windows Sockets Asynchronous)异步套接字
if (WSAStartup(sockVersion, &wsaData) != 0)
return;
m_clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_clientSocket == INVALID_SOCKET)
{
MessageBox("Invalid Socket!", "错误", MB_ICONERROR);
return;
}
//建立一个客户端地址
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8888);
serAddr.sin_addr.S_un.S_addr = inet_addr("127.1.0.1");
//客户端向服务端请求连接
if (connect(m_clientSocket, (sockaddr*)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{
MessageBox("Connect Error!!", "错误", MB_ICONERROR);
closesocket(m_clientSocket);
return;
}
//与服务端连接成功,开始发送消息
//char sendToServerBuff[1024] = "服务端,我来啦~";
char sendToServerBuff[1024];
//初始化stuInfo类对象
StudentInfo stuInfo;
stuInfo.SetId(111);
stuInfo.SetName("abcdefzzzzz");
stuInfo.SetSex(true);
send(m_clientSocket, (char*)&stuInfo, sizeof(StudentInfo), 0);
//send(m_clientSocket, *(&sendToServerBuff), sizeof(sendToServerBuff), 0);
//接收服务端返回的消息
char buffFromServer[1024];
int recvDataLen = recv(m_clientSocket, buffFromServer, sizeof(buffFromServer), 0);
if (recvDataLen > 0)
{
MessageBox(buffFromServer);
}
closesocket(m_clientSocket);
WSACleanup();
}
以上于2022.4.6更新。
(未完待续...)
有任何问题和改进建议可私信或评论留言!