其实网络编程一开始都搞过
只不过当时 精力都在CTF上面 一直想写一些小玩意=== 但是都没有空--
所以现在打算抽两天空写一哈===
最后也算是写完了
其实一开始打算用的是选择模型 最后感觉这个还是比较好玩的 就 打算用这个模型写一哈==
关于 各个模型的介绍
https://blog.csdn.net/qq_41071646/article/details/90414289
然后开始 ==
先说一下程序的大概流程
有一个服务端 来设置SOCKER 然后 进行信息的发送=
然后有客服端
进行信息的发送和接收
不过这里我倒是发现了一个bug 就是如果不主动发送信息的话 就一直接收不到信息 ==
等有空更新一哈==
服务端:
类的设计
class my_server
{
public:
void init();
void set();
void S_accept();
void recvdata();
SOCKET m_SockServer, m_SockClient;
SOCKET m_Clients[10];
int m_ConnectNum;
char m_IP[100];
UINT m_Port;
HWND Hwnd;
};
这里其实都明了了=
下面是这些函数--
inline void my_server::init()
{
m_SockServer = socket(AF_INET, SOCK_STREAM, 0);
WSAAsyncSelect(m_SockServer, Hwnd, WM_SOCKET, FD_WRITE | FD_READ | FD_ACCEPT);
m_ConnectNum = 0;
for (int i = 0; i< 10; i++)
m_Clients[i] = 0;
}
inline void my_server::set()
{
char strport[100];
GetDlgItemText(Hwnd, IDC_connect, m_IP, 98);
OutputDebugStringA(m_IP);
GetDlgItemText(Hwnd, IDC_Port, strport, 8);
m_Port = atoi(strport);
sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.S_un.S_addr = inet_addr(m_IP);
serveraddr.sin_port = htons(m_Port);
if (bind(m_SockServer, (sockaddr*)&serveraddr, sizeof(serveraddr)))
{
MessageBox(NULL,"绑定地址失败.","警告",0);
return;
}
else
{
MessageBox(NULL, "绑定地址成功.", "恭喜", 0);
}
listen(m_SockServer, 20);
}
inline void my_server::S_accept()
{
SOCKADDR clientAddr;
int clientAddr_size = sizeof(clientAddr);
if (m_ConnectNum<10)
{
m_Clients[m_ConnectNum] = ::accept(m_SockClient, (SOCKADDR*)&clientAddr, &clientAddr_size);
::WSAAsyncSelect(m_Clients[m_ConnectNum], Hwnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE);
m_ConnectNum++;
}
else
{
SOCKET clientSock = accept(m_SockClient, (SOCKADDR*)&clientAddr, &clientAddr_size);
char* str = "聊天室人数达到上线";
send(clientSock, str, strlen(str) + sizeof(char), NULL);
closesocket(clientSock);
}
}
inline void my_server::recvdata()
{
char buffer[1024];
int num = -1;
int curlink = -1;
for (int i = 0; i < 10; i++)
{
num = recv(m_Clients[i], buffer, 1024, 0);
if (num != -1)
{
curlink = i;
break;
}
}
buffer[num] = 0;
for (int j = 0; j < m_ConnectNum; j++)
if (j != curlink)
send(m_Clients[j], buffer, num, 0);
return;
}
然后在主函数里面
在程序初始化的时候我们把 WAS 类 初始化一下
回调函数里面的主要代码
if (UMsg == WM_INITDIALOG)
{
WSADATA wsd;
WSAStartup(MAKEWORD(2, 2), &wsd);
Server.Hwnd = hwndDlg;
Server.m_ConnectNum = 0;
Server.init();
}
if (UMsg==WM_SOCKET)
{
Server.m_SockClient = wParam;
// 查看是否出错
if (WSAGETSELECTERROR(lParam))
{
::closesocket(Server.m_SockClient);
return 0;
}
// 处理发生的事件
switch (WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT: // 监听中的套接字检测到有连接进入
{
Server.S_accept();
}
break;
case FD_WRITE:
{
}
break;
case FD_READ:
{
Server.recvdata();
}
break;
case FD_CLOSE:
{
::closesocket(Server.m_SockClient);
}
break;
}
}
else if (WM_INPUT == UMsg)
{
}
if (UMsg == WM_CLOSE)
{
WSACleanup();
EndDialog(hwndDlg, NULL);
}
if (UMsg == WM_COMMAND)
{
if (wParam == IDSet)//点击的设置按钮
{
Server.set();
}
}
然后就是 客服端
类的设计
class client
{
public:
void login();
void Onsend();
void recvdata();
char m_IP[100];
UINT m_Port;
HWND Hwnd;
SOCKET m_SockClient;
char name[100];
HWND L_hwnd;
};
主要函数
inline void client::login()
{
sockaddr_in serveraddr;
char strport[100];
GetDlgItemText(Hwnd, IDC_IP, m_IP, 98);
OutputDebugStringA(m_IP);
OutputDebugString("\n");
GetDlgItemText(Hwnd, IDC_Port, strport, 8);
m_Port = atoi(strport);
OutputDebugStringA(strport);
OutputDebugString("\n");
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.S_un.S_addr = inet_addr(m_IP);
serveraddr.sin_port = htons(m_Port);
if (connect(m_SockClient, (sockaddr*)&serveraddr, sizeof(serveraddr)) != 0)
{
MessageBox(NULL, "登陆失败.", "警告", 0);
return;
}
else
{
MessageBox(NULL, "登陆成功.", "恭喜", 0);
}
::WSAAsyncSelect(m_SockClient, Hwnd, WM_SOCKET, FD_READ);
char info[100];
GetDlgItemText(Hwnd, IDC_Name, name, 98);
wsprintf(info, "%s------>%s", name, "进入聊天室");
send(m_SockClient, info, strlen(info) + sizeof(char), 0);/**/
}
inline void client::Onsend()
{
char sendlist[100],info[100];
GetDlgItemText(Hwnd, IDC_eGo, sendlist, 98);
wsprintf(info, "%s说: %s", name, sendlist);
send(m_SockClient, info, strlen(info) + sizeof(char), 0);
L_hwnd = GetDlgItem(Hwnd, IDC_list);
SendMessage(L_hwnd, LB_ADDSTRING, NULL, (LPARAM)info);
}
inline void client::recvdata()
{
char buffer[1024];
int num = recv(m_SockClient, buffer, 1024, 0);
buffer[num] = 0;
SendMessage(L_hwnd, LB_ADDSTRING, NULL, (LPARAM)buffer);
}
回调函数里面的主要代码
if (UMsg == WM_INITDIALOG)
{
WSADATA wsd;
WSAStartup(MAKEWORD(2, 2), &wsd);
Client.m_SockClient = socket(AF_INET, SOCK_STREAM, 0);
Client.Hwnd = hwndDlg;
}
if (UMsg == WM_CLOSE)
{
WSACleanup();
EndDialog(hwndDlg, NULL);
}
if (UMsg == WM_COMMAND)
{
if (wParam == IDC_Login)//点击的设置按钮
{
Client.login();
}
if (wParam == IDC_Go)
{
Client.Onsend();
}
}
if (UMsg == WM_SOCKET)
{
switch (WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT: // 监听中的套接字检测到有连接进入
{
}
break;
case FD_WRITE:
{
}
break;
case FD_READ:
{
Client.recvdata();
}
break;
case FD_CLOSE:
{
}
break;
}
}
总体来说 代码很简单
也算是更加清晰的认清了 这个模型 感觉挺好玩的=== 能和消息机制结合到一块
参考资料
《Visual C++ 从入门到精通》
《Windows网络与通信程序设计》