其實網絡編程一開始都搞過
只不過當時 精力都在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網絡與通信程序設計》