我今天写的是通过windows的api搭建界面和效果的实现 代码分为服务器端的代码,客户端的代码
客户端和服务器代码结构分为 1.界面绘制 2.网络通信模块 3.多线程管理模块 4.消息处理模块
//客户端代码
#include <Windows.h>
#include <string.h>
#include <tchar.h>
#include <stdio.h>
#include <Commctrl.h>
#pragma comment(lib,"wsock32.lib")
#include<Windows.h>
#include<iostream>
#include<string>
#define ID_STATE 1
#define ID_TEXTLIST 2
#define ID_SENDTEXT 3
#define ID_CLOSE 4
#define ID_SEND 5
#define ID_CONNECT 6
#define ID_CLOSELINK 7
#define ID_IP 8
#define ID_CLIENTLIST 9
//全局变量
TCHAR szClassName[] = TEXT("MyWindowClass"); //窗口类名
TCHAR szWindowName[] = TEXT("网络聊天室—-客户端"); //窗口标题名
HWND hdlg;
HWND hwnd,hSendText,hSendBtn,hTextList,hCloseBtn,hConnectBtn,hIpInput,hState,hCloseLinkBtn,hClientList,hSendTip;
WSADATA wsaData;
SOCKET Remote;
sockaddr_in RemoteAdd;
HANDLE ThdConnect,ThdRecv,ThdSend; //三个线程句柄
SYSTEMTIME sysTime;//保存本地时间信息
bool isClose=true;//判断程序是否结束
//HMENU hmenu,hpopup;
char sendToIp[20]="所有人";//保存接收消息的客户端ip
//函数声明
ATOMMyRegisterClass(HINSTANCE hInstance); // 定义及注册窗口类函数
BOOLInitInstance(HINSTANCE, int); // 初始化函数(创建并显示窗口)
LRESULT CALLBACKWndProc(HWND, UINT, WPARAM, LPARAM); // 窗口函数
DWORD WINAPI ThreadConnect(LPVOID p);
DWORD WINAPI ThreadRecv(LPVOID p);
DWORD WINAPI ThreadSend(LPVOID p);
//****入口函数*************************************
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
//运行定义及注册窗口类的函数
MyRegisterClass(hInstance);
//执行应用程序初始化
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
//主消息循环
while(GetMessage(&msg, NULL, 0, 0)) //从消息队列中取出消息
{
TranslateMessage(&msg); // 将按键消息转换为字符消息
DispatchMessage(&msg); // 将消息发送到相应的窗口函数
}
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
return (int)msg.wParam; // 当GetMessage返回0时程序结束,将MSG的wParam参数返回操作系统
}
//****定义及注册窗口类函数*************************
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASS wc;
// 用描述主窗口的参数填充WNDCLASS结构
wc.style = CS_HREDRAW|CS_VREDRAW; // 指定如果窗口大小改变就重绘
wc.lpfnWndProc = WndProc; // 窗口函数指针
wc.cbClsExtra = 0; // 没有额外的类内存
wc.cbWndExtra = 0; // 没有额外的窗口内存
wc.hInstance = hInstance; // 实例句柄
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 使用预定义图标
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 使用预定义光标
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 使用白色背景画刷
wc.lpszMenuName = NULL; // 不指定菜单
wc.lpszClassName = szClassName ; // 窗口类的名称
return RegisterClass(&wc); //注册窗口类,如果成功则返回一个atom值,失败则返回0
}
//****初始化函数************************************
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
//句柄是窗口的标识,设置控件都要指定句柄上
hwnd = CreateWindow(szClassName, szWindowName, WS_OVERLAPPEDWINDOW,
300,100, 700, 550, NULL, NULL, hInstance, NULL);
if (!hwnd)
{
return FALSE;
}
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
//连接状态
hState=CreateWindowA("static","连接状态:等待连接",WS_VISIBLE|WS_CHILD,
10,10,150,20,hwnd,(HMENU)1,hInstance,NULL);
//提示
CreateWindowA("static","请选择发送对象",WS_VISIBLE|WS_CHILD,
480,10,120,20,hwnd,(HMENU)1,hInstance,NULL);
//历史记录
hTextList=CreateWindowA("edit",NULL,WS_CHILD|WS_VISIBLE|WS_BORDER|
ES_MULTILINE|ES_AUTOVSCROLL|WS_VSCROLL,
10,30,450,300,hwnd,(HMENU)2,hInstance,NULL);
//发送文本框
hSendText=CreateWindowA("edit",NULL,WS_CHILD|WS_VISIBLE|WS_BORDER|
ES_MULTILINE|ES_AUTOVSCROLL|WS_VSCROLL,
10,360,450,100,hwnd,(HMENU)3,hInstance,NULL);
//"关闭"按钮
hCloseBtn=CreateWindowA("button","关闭",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
300,465,50,25,hwnd,(HMENU)4,hInstance,NULL);
//"发送"按钮
hSendBtn=CreateWindowA("button","发送",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_DISABLED,
390,465,50,25,hwnd,(HMENU)5,hInstance,NULL);
//"连接"按钮
hConnectBtn=CreateWindowA("button","连接",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
300,333,50,25,hwnd,(HMENU)6,hInstance,NULL);
//ip提示框
CreateWindowA("static","服务器IP",WS_VISIBLE|WS_CHILD ,
10,335,60,20,hwnd,NULL,hInstance,NULL);
//"断开"按钮
hCloseLinkBtn=CreateWindowA("button","断开",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_DISABLED,
400,333,50,25,hwnd,(HMENU)7,hInstance,NULL);
//ip框
hIpInput=CreateWindowA("edit","",WS_CHILD|WS_VISIBLE|WS_BORDER,
90,335,100,20,hwnd,(HMENU)8,hInstance,NULL);
//列表
hClientList=CreateWindowA("listbox","列表",WS_CHILD|WS_VISIBLE|LBS_HASSTRINGS|LBS_NOTIFY ,
480,35,150,305,hwnd,(HMENU)9,hInstance,NULL);
hSendTip=CreateWindowA("static","当前发送目标:所有人",WS_VISIBLE|WS_CHILD,
10,467,230,20,hwnd,NULL,hInstance,NULL);
//创建菜单项
//hmenu=CreateMenu() ;
//hpopup=CreatePopupMenu();
//AppendMenu(hpopup,MF_STRING,10,TEXT("&发送给所有人"));
//AppendMenu(hpopup,MF_STRING,11,TEXT("&与TA私聊"));
//AppendMenu(hpopup,MF_STRING,12,TEXT("&取消"));
//AppendMenu(hmenu,MF_POPUP,(int)hpopup,NULL);
SetWindowTextA(hIpInput,"127.0.0.1");
return TRUE;
}
//****窗口函数**************************************
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)//句柄 消息 传递整数,句柄或标志位 传递整数,指针或结构体信息
{
HDC hdc;
PAINTSTRUCT ps;
static char ipAdd[20];
POINT point;
static HBITMAP hBitmap;
static BITMAP bg;
static HDC hdcMem;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
SelectObject(hdcMem,hBitmap);
BitBlt(hdc,0,0,bg.bmWidth,bg.bmHeight,hdcMem,0,0,SRCCOPY);
EndPaint(hwnd, &ps);
return 0;
case WM_CREATE:
{
//初始化
WSAStartup(MAKEWORD(2,0),&wsaData);
//RemoteAdd.sin_family=AF_INET;
//RemoteAdd.sin_port=htons(12057);
//Remote=socket(AF_INET,SOCK_STREAM,0);
hBitmap=(HBITMAP)LoadImage(NULL,TEXT("pic\\\\bg.BMP"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE);//背景图
GetObject(hBitmap,sizeof(BITMAP),&bg);
hdc=GetDC(hwnd);
hdcMem=CreateCompatibleDC(hdc);
ReleaseDC(hwnd,hdc);
}
return 0;
case WM_MOUSEMOVE://鼠标移动消息
point.x=LOWORD(lParam);//水平方向坐标 HIWORD相当于要高的8位数据 LOWORD要数据低的八位
point.y=HIWORD(lParam);//垂直方向坐标
return 0;
case WM_COMMAND://用户与组件交互的信号
if ( HIWORD(wParam)==LBN_DBLCLK )
{
int i=SendMessageA(hClientList,LB_GETCURSEL,0,0);//得到选择项的索引
SendMessageA(hClientList,LB_GETTEXT,i,(LPARAM)sendToIp);//根据索引得到内容
char a[30];
strcpy(a,"当前发送目标: ");
strcat(a,sendToIp);
SetWindowTextA(hSendTip,a);//提示发送对象
}
switch(LOWORD(wParam))
{
case ID_CONNECT:
{
GetWindowTextA(hIpInput,ipAdd,21);
EnableWindow(hConnectBtn,0);
if ( strlen(ipAdd)<8)
{
MessageBoxA(hwnd,"IP地址输入错误,请重新输入.","错误",MB_OK);
return 0;
}
RemoteAdd.sin_addr.S_un.S_addr=inet_addr(ipAdd);
ThdConnect=CreateThread(NULL,NULL,ThreadConnect,NULL,NULL,NULL);//创建连接的线程
}
return 0;
case ID_CLOSELINK:
{
isClose=true;
char cBuff[2]={'q','#'};
send(Remote,cBuff,3,0);
EnableWindow(hConnectBtn,1);//让控件显示
EnableWindow(hCloseLinkBtn,0);//让控件关闭
SetWindowTextA(hState,"连接状态:未连接");
EnableWindow(hSendBtn,0);
EnableWindow(hIpInput,1);
SendMessageA(hClientList,LB_RESETCONTENT ,0,0);
//WaitForSingleObject(&ThdRecv,INFINITE);
//closesocket(Remote);
//WSACleanup();
}
return 0;
case ID_CLOSE:
{
char cBuff[2]={'q','#'};
send(Remote,cBuff,3,0);
closesocket(Remote);
WSACleanup();
SendMessage(hwnd,WM_CLOSE,0,0);
}
return 0;
case ID_SEND:
if ( strcmp(sendToIp,ipAdd)==0 )
{
MessageBoxA(hwnd,"不允许和自己私聊!","提示",MB_OK);
return 0;
}
if (strcmp(sendToIp,"所有人")==0)
{
///CreateThread(NULL,NULL,ThreadSend,NULL,NULL,NULL);//创建线程负责发送数据
char szText[99999];
char cBuff[2000];
TCHAR Time[15];
GetWindowTextA(hSendText, cBuff, 1950);//获取需要发送的内容
send(Remote, cBuff, strlen(cBuff) + 1, 0);//开始发送
}
else
{
//CreateThread(NULL,NULL,ThreadSend,(LPVOID)sendToIp,NULL,NULL);//创建线程负责发送数据
char szText[99999];
char cBuff[2000];
TCHAR Time[15];
GetWindowTextA(hSendText, cBuff, 1950);//获取需要发送的内容
std::string str = cBuff;
str += "wmsl";
str += sendToIp;
str += "#";
str += cBuff;
send(Remote, str.c_str(), str.size() + 1, 0);//开始发送
}
return 0;
default:
return 0;
}
return 0;
case WM_DESTROY:
PostQuitMessage(0) ;
return 0 ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
//此为建立连接的线程
DWORD WINAPI ThreadConnect(LPVOID p)
{
RemoteAdd.sin_family = AF_INET;
RemoteAdd.sin_port = htons(12057);
Remote = socket(AF_INET, SOCK_STREAM, 0);
if ( connect(Remote,(sockaddr*)&RemoteAdd,sizeof(RemoteAdd))==-1 )
{
MessageBoxA(hwnd,"连接服务器失败,请检查IP地址是否正确","连接失败",MB_OK);
EnableWindow(hConnectBtn,1);
return 0;
}
EnableWindow(hSendBtn,1);
EnableWindow(hConnectBtn,0);
EnableWindow(hSendText,1);
EnableWindow(hIpInput,0);
EnableWindow(hCloseLinkBtn,1);
SetWindowTextA(hState,"连接状态:已连接");
isClose=false;
ThdRecv=CreateThread(NULL,NULL,ThreadRecv,NULL,NULL,NULL); //连接成功则创建接收数据的线程
return 0;
}
//此为接收数据的线程
DWORD WINAPI ThreadRecv(LPVOID p)
{
char szText[99999];
while(!isClose)
{
char Time[30];
char cBuff[255];
int n=0;
n=recv(Remote,cBuff,256,0);
cBuff[n]='\\0';
//判断消息是否为命令消息
if ( cBuff[0]=='y' && cBuff[1]=='#' )//关闭
{
break;
}
//获取列表
if ( cBuff[0]=='k' && cBuff[1]=='h' && cBuff[2]=='i' && cBuff[3]=='p' )
{
SendMessageA(hClientList,LB_RESETCONTENT ,0,0);//清空客户端列表,然后重新添加
SendMessageA(hClientList,LB_ADDSTRING,0,(LPARAM)"所有人");
char a[21];
strcpy(a,"");
//依次取出每个客户端IP
for ( int i=4; cBuff[i]!='\\0'; i++)
{
if ( cBuff[i]!='#')//遇到字符"#"说明获取到了一个完整的IP地址
{
char temp[2];
sprintf(temp,"%c",cBuff[i]);
strcat(a,temp);
}
else
{
SendMessageA(hClientList,LB_ADDSTRING,0,(LPARAM)a);
strcpy(a,"");
}
}
continue;
}
GetWindowTextA(hTextList,szText,99999);//获取历史记录文本框中的内容
GetLocalTime(&sysTime);
//格式化输出时间
sprintf(Time,"%d:%d:%d",sysTime.wHour,sysTime.wMinute,sysTime.wSecond);
strcat(szText,Time);
strcat(szText,"\\r\\n"); //换行
strcat(szText,cBuff);
strcat(szText,"\\r\\n\\r\\n"); //换行
SetWindowTextA(hTextList,szText);
}
EnableWindow(hSendBtn,0);
EnableWindow(hConnectBtn,1);
EnableWindow(hSendText,0);
EnableWindow(hIpInput,1);
EnableWindow(hCloseLinkBtn,0);
SetWindowTextA(hState,"连接状态:未连接");
return 0;
}
此为发送数据的线程
//DWORD WINAPI ThreadSend(LPVOID p)
//{
//
//return 0;
//}
//服务器端代码
#include <Windows.h>
#include <TOM.h>
#include <string.h>
#include <tchar.h>
#include <stdio.h>
#include <map>
#define ID_STATIC 1
#define ID_TEXT 2
#define ID_TEXTSEND 3
#define ID_CLOSE 4
#define ID_SEND 5
#define ID_LISTEN 6
#define ID_CLIENTLIST 7
#define ID_TIMER1 10
using namespace std;
#pragma comment(lib,"wsock32.lib")
//全局变量
TCHAR szClassName[] = TEXT("MyWindowClass"); //窗口类名
TCHAR szWindowName[] = TEXT("网络聊天室—服务器"); //窗口标题名
HWND hdlg;
HWND hwnd;
WSADATA wsaData;
SOCKET srv;//本地套接字
sockaddr_in sockin;//本地地址信息
HANDLE ThdAccept,ThdSend; //线程句柄
SYSTEMTIME sysTime;//时间信息
HWND hTip,hTextList,hSendText,hCloseBtn,hSendBtn,hListenBtn,hClientList;//各个控件句柄
map<SOCKET,sockaddr_in> allClients;//客户端套接字和地址信息的一一映射
char szClientList[25010];//保存客户端IP串,用于客户端获取
//函数声明
ATOMMyRegisterClass(HINSTANCE hInstance); // 定义及注册窗口类函数
BOOLInitInstance(HINSTANCE, int); // 初始化函数(创建并显示窗口)
LRESULT CALLBACKWndProc(HWND, UINT, WPARAM, LPARAM); // 窗口函数
BOOL CALLBACK DlgProc (HWND hDlg, UINT message,WPARAM wParam, LPARAM lParam);
DWORD WINAPI ThreadAccept(LPVOID p);
DWORD WINAPI ThreadRecv(LPVOID p);
DWORD WINAPI ThreadSend(LPVOID p);
DWORD WINAPI ThreadUpdate(LPVOID p);
//****入口函数*************************************
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstanc,LPSTR lpCmdLine,int nCmdShow)
{
MSG msg;
//运行定义及注册窗口类的函数
MyRegisterClass(hInstance);
//执行应用程序初始化
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
//主消息循环
while(GetMessage(&msg, NULL, 0, 0)) //从消息队列中取出消息
{
TranslateMessage(&msg); // 将按键消息转换为字符消息
DispatchMessage(&msg); // 将消息发送到相应的窗口函数
}
return (int)msg.wParam; // 当GetMessage返回0时程序结束,将MSG的wParam参数返回操作系统
}
//****定义及注册窗口类函数*************************
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASS wc;
// 用描述主窗口的参数填充WNDCLASS结构
wc.style = CS_HREDRAW|CS_VREDRAW; // 指定如果窗口大小改变就重绘
wc.lpfnWndProc = WndProc; // 窗口函数指针
wc.cbClsExtra = 0; // 没有额外的类内存
wc.cbWndExtra = 0; // 没有额外的窗口内存
wc.hInstance = hInstance; // 实例句柄
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 使用预定义图标
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 使用预定义光标
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 使用白色背景画刷
wc.lpszMenuName = NULL; // 不指定菜单
wc.lpszClassName = szClassName ; // 窗口类的名称
return RegisterClass(&wc); //注册窗口类,如果成功则返回一个atom值,失败则返回0
}
//****初始化函数************************************
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hwnd = CreateWindow(szClassName, szWindowName, WS_OVERLAPPEDWINDOW,
200,50,670, 550, NULL, NULL, hInstance, NULL);
if (!hwnd)
{
return FALSE;
}
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
//创建所需控件
hTip=CreateWindowA("static","连接状态:等待监听",WS_VISIBLE|WS_CHILD,
10,10,150,20,hwnd,(HMENU)1,hInstance,NULL);
hTextList=CreateWindowA("edit","",WS_CHILD|WS_VISIBLE|WS_BORDER|
ES_MULTILINE|ES_AUTOVSCROLL|WS_VSCROLL,
10,30,450,300,hwnd,(HMENU)2,hInstance,NULL);
hSendText=CreateWindowA("edit","",WS_CHILD|WS_VISIBLE|WS_BORDER|
ES_MULTILINE|ES_AUTOVSCROLL|WS_VSCROLL,
10,350,450,100,hwnd,(HMENU)3,hInstance,NULL);
hCloseBtn=CreateWindowA("button","关闭",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
300,455,50,25,hwnd,(HMENU)4,hInstance,NULL);
hSendBtn=CreateWindowA("button","发送",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_DISABLED,
390,455,50,25,hwnd,(HMENU)5,hInstance,NULL);
hListenBtn=CreateWindowA("button","监听",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
400,5,50,25,hwnd,(HMENU)6,hInstance,NULL);
CreateWindowA("static","客户端列表",WS_VISIBLE|WS_CHILD ,
490,8,100,20,hwnd,NULL,hInstance,NULL);
hClientList=CreateWindowA("listbox","列表",WS_CHILD|WS_VISIBLE|LBS_HASSTRINGS|LBS_NOTIFY ,
480,35,150,305,hwnd,(HMENU)7,hInstance,NULL);
return TRUE;
}
//****窗口函数**************************************
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static HBITMAP hBitmap;
static BITMAP bg;
static HDC hdcMem;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
SelectObject(hdcMem,hBitmap);
BitBlt(hdc,0,0,bg.bmWidth,bg.bmHeight,hdcMem,0,0,SRCCOPY);
EndPaint(hwnd, &ps);
return 0;
case WM_CREATE:
{
//初始化
WSAStartup(MAKEWORD(2,0),&wsaData);
sockin.sin_family=AF_INET;
sockin.sin_port=htons(12057);
sockin.sin_addr.S_un.S_addr=INADDR_ANY;
srv=socket(AF_INET,SOCK_STREAM,0);
hBitmap=(HBITMAP)LoadImage(NULL,TEXT("pic\\\\bg.BMP"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
GetObject(hBitmap,sizeof(BITMAP),&bg);
hdc=GetDC(hwnd);
hdcMem=CreateCompatibleDC(hdc);
ReleaseDC(hwnd,hdc);
strcat(szClientList,"khip");//设置消息头
}
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_LISTEN:
{
if (bind(srv,(LPSOCKADDR)&sockin,sizeof(sockin))==SOCKET_ERROR )
{
MessageBox(hwnd,TEXT("控制端口被占用,监听失败!"),TEXT("失败"),MB_OK);
WSACleanup();
return 0;
}
if (listen(srv,2)==SOCKET_ERROR)
{
MessageBox(hwnd,TEXT("监听失败!"),TEXT("失败"),MB_OK);
WSACleanup();
return 0;
}
EnableWindow(hListenBtn,0);//设置按钮无效
SetWindowTextA(hTip,"连接状态:等待连接");//设置静态文本内容
ThdAccept=CreateThread(NULL,NULL,ThreadAccept,NULL,NULL,NULL);//创建接受连接的线程
return 0;
}
case ID_CLOSE:
SendMessage(hwnd,WM_CLOSE,0,0);
return 0;
case ID_SEND:
CreateThread(NULL,NULL,ThreadSend,NULL,NULL,NULL);//发送数据
return 0;
}
return 0;
case WM_DESTROY:
KillTimer(hwnd,ID_TIMER1);
PostQuitMessage(0);
return 0 ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
//此为接受客户端连接的线程
DWORD WINAPI ThreadAccept(LPVOID p)
{
while(true)
{
SOCKET client;
sockaddr_in clientAdd;
int addrlen=sizeof(clientAdd);
client=accept(srv,(SOCKADDR*)&clientAdd,&addrlen);//接受客户端连接
if (client==INVALID_SOCKET)
{
WSACleanup();
EnableWindow(hListenBtn,1);
}
else
{
EnableWindow(hSendBtn,1);
CreateThread(NULL,NULL,ThreadRecv,(LPVOID)client,NULL,NULL); //连接成功则创建接收数据的线程
allClients[client]=clientAdd;
char a[30];
sprintf(a,"当前连接客户端:%d 个",allClients.size());
SetWindowTextA(hTip,a);//提示连接个数
sprintf(a,"%s",inet_ntoa(clientAdd.sin_addr));
SendMessageA(hClientList,LB_ADDSTRING,0,(LPARAM)a);//设置客户端列表
strcat(szClientList,a);
strcat(szClientList,"#");
CreateThread(NULL,NULL,ThreadUpdate,NULL,NULL,NULL);
}
}
return 0;
}
//此为接收数据的线程
DWORD WINAPI ThreadRecv(LPVOID p)
{
char szText[99999];
while(true)
{
char Time[15];
char cBuff[2000];
recv((SOCKET)p,cBuff,2000,0);
//客户端请求断开
if (cBuff[0]=='q' && cBuff[1]=='#')
{
break;
}
//客户端请求私聊
if (cBuff[0]=='w' && cBuff[1]=='m' && cBuff[2]=='s' && cBuff[3]=='l')
{
char sendToIp[20];//目标IP
char a[50];
strcpy(sendToIp,"");
int i;
for (i=4; cBuff[i]!='#'; i++)
{
char temp[2];
strcpy(temp,"");
sprintf(temp,"%c",cBuff[i]);//取出目标IP,
strcat(sendToIp,temp);
}
//设置接收方所需数据
char *cTemp=new char[strlen(cBuff)];
strcpy(cTemp,sendToIp);
strcat(cTemp,"#");
sprintf(a,"%s悄悄对我说:\\r\\n",inet_ntoa(allClients[(SOCKET)p].sin_addr));
strcat(cTemp,a);
strcat(cTemp,cBuff+i+1);
CreateThread(NULL,NULL,ThreadSend,(LPVOID)cTemp,NULL,NULL);//发送数据
//显示客户端私聊信息
GetWindowTextA(hTextList,szText,99999);//获取历史记录文本框中的内容
GetLocalTime(&sysTime);
sprintf(Time,"%d:%d:%d",sysTime.wHour,sysTime.wMinute,sysTime.wSecond);
strcat(szText,Time);
strcat(szText,"\\r\\n");
sprintf(a,"%s悄悄对%s说:\\r\\n",inet_ntoa(allClients[(SOCKET)p].sin_addr),sendToIp);
strcat(szText,a);
strcat(szText,cBuff+i+1);
strcat(szText,"\\r\\n\\r\\n"); //换行
SetWindowTextA(hTextList,szText);
//回应私聊方私聊成功
char *Temp=new char[strlen(cBuff)];
strcpy(Temp,"");
sprintf(a,"我对%s悄悄说:\\r\\n",sendToIp);
strcat(Temp,a);
strcat(Temp,cBuff+i+1);
send((SOCKET)p,Temp,strlen(Temp)+4,0);
continue;
}
GetWindowTextA(hTextList,szText,99999);//获取历史记录文本框中的内容
GetLocalTime(&sysTime);
//格式化输出时间
sprintf(Time,"%d:%d:%d",sysTime.wHour,sysTime.wMinute,sysTime.wSecond);
strcat(szText,Time);
strcat(szText,"\\r\\n");
char *a=new char[strlen(cBuff)+20];
sprintf(a,"%s对大家说:",inet_ntoa(allClients[(SOCKET)p].sin_addr));
strcat(a,cBuff);
for (map<SOCKET,sockaddr_in> ::iterator itr=allClients.begin(); itr!=allClients.end(); itr++)
{
send(itr->first,a,strlen(a)+1,0);
}
strcat(szText,a);
strcat(szText,"\\r\\n\\r\\n"); //换行
SetWindowTextA(hTextList,szText); //设置历史记录
}
//当此客户端断开连接后执行以下操作
allClients.erase(allClients.find((SOCKET)p));//移除断开的客户端信息
char a[30];
sprintf(a,"当前连接客户端:%d 个",allClients.size());
SetWindowTextA(hTip,a);
//更新客户端列表
SendMessage(hClientList,LB_RESETCONTENT ,0,0);//清空列表;
strcpy(szClientList,"khip");//设置消息头
for( map<SOCKET,sockaddr_in> ::iterator itr=allClients.begin(); itr!=allClients.end(); itr++)
{
char a[60];//遍历当前连接的客户端,设置客户端列表
sprintf(a,"%s",inet_ntoa(itr->second.sin_addr));
SendMessageA(hClientList,LB_ADDSTRING,0,(LPARAM)a);
//printf("%s\\n",a);
//将各个客户端IP添加到IP字符串中
strcat(szClientList,a);
strcat(szClientList,"#");
}
CreateThread(NULL,NULL,ThreadUpdate,NULL,NULL,NULL);
return 0;
}
//此为发送数据的线程
DWORD WINAPI ThreadSend(LPVOID p)
{
char szText[99999] ;
char cBuff[2100];
char Time[15];
if ( p )
{
int i,j;
strcpy(cBuff,"");
strcpy(cBuff,(char*)p);
char a[30];
strcpy(a,"");
for (j=0; cBuff[j]!='#'; j++)
{
char temp[2];
sprintf(temp,"%c",cBuff[j]);
strcat(a,temp);
}
i=SendMessageA(hClientList,LB_FINDSTRING,-1,(LPARAM)a);// 从列表中查找目标IP
map<SOCKET,sockaddr_in> ::iterator itr=allClients.begin();// 根据目标IP的位置从映射中找到其SOCKET
for (int k=0; k!=i; k++)
{
itr++;
}
send(itr->first,cBuff+j+1,strlen(cBuff),0);//在找到的SOCKET上发送消息
return 0;
}
GetWindowTextA(hSendText,cBuff,2000);//获取需要发送的内容
SetWindowTextA(hSendText,"");
GetWindowTextA(hTextList,szText,99999);//获取历史记录文本框中的内容
GetLocalTime(&sysTime);
//格式化输出时间
sprintf(Time,"%d:%d:%d",sysTime.wHour,sysTime.wMinute,sysTime.wSecond);
strcat(szText,Time);
strcat(szText,"\\r\\n");
char *a=new char[2020];
strcpy(a,"");
strcat(a,"服务器对大家说:");
strcat(a,cBuff);
for (map<SOCKET,sockaddr_in> ::iterator itr=allClients.begin(); itr!=allClients.end(); itr++)
{
send(itr->first,a,strlen(a)+1,0);
}
strcat(szText,a);
strcat(szText,"\\r\\n"); //换行
SetWindowTextA(hTextList,szText); //设置历史记录
delete []a;
return 0;
}
//更新信息
DWORD WINAPI ThreadUpdate(LPVOID p)
{
//将信息更新至每个客户端
for( map<SOCKET,sockaddr_in> ::iterator itr=allClients.begin(); itr!=allClients.end(); itr++)
{
send(itr->first,szClientList,strlen(szClientList)+1,0);
}
return 0;
}
接下来我要讲解一下大概原理 windows是通过消息来传递信号,你可以理解为有人给你敲门敲门的声音就是消息(消息事件),然后你听到后就有相应的操作(对应的消息处理函数) 你处理完事情后是不是当前状态就变化了,所以你就该刷新一下窗口改变状态 这样我们就有了基础的交互界面和交互处理函数了
你可以自定义消息宏如下
#define ID_STATE 1 #define ID_TEXTLIST 2 #define ID_SENDTEXT 3
你也可以自定义处理消息函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 接下来我们要做的是网络通信部分,我们使用socket方式去连接 1.创建套接字socket 2.sockaddr_in设置端口和ip 3.连接connect 4.线程发送send和接收单独一个线程recv(会阻塞等待接受到消息)
评论前必须登录!
注册