#include "stdafx.h"
#include <windows.h>
#include <windowsx.h>
#include <winsock2.h>
#include "resource.h"
#include "MainDlg.h"
#include "chart.h"
#include "Commctrl.h"
#include "mmsystem.h"
#include "shellapi.h"
#pragma comment(lib, "wsock32.lib")
#define HIGHTIME	21968699 // 21968708 // Jan 1, 1900 FILETIME.highTime
#define LOWTIME	4259332096 // 1604626432 // Jan 1, 1900 FILETIME.lowtime
#define WM_MYMESSAGE WM_USER+100         //自定义消息 最小化
typedef struct IpInfo
{
	SOCKET sock;
	HWND hwnd;
}IpInfo;
typedef struct ClSocket					//用户列表
{
	SOCKET Sock;
	HANDLE handle;
	ClSocket* next;
}ClSocket;
typedef struct SendAllInfo
{
	ClSocket *SockList;
	HWND hwnd;
	TCHAR Msg[255];
}SendAllInfo;
//含结构体不好在.h文件中声明的函数区
void AddUserSock(ClSocket* UserList,SOCKET addsock,HANDLE addhandle);
void DelUserSock(ClSocket* UserList,SOCKET delsock);
SOCKET c_sock;									//本地聊天用套接字
SOCKADDR_IN AdIp;
SOCKADDR_IN sa;
WSADATA wsaData;
SOCKET sock;
TCHAR HostName[50];
TCHAR PORT[8];
struct hostent* Mhost = NULL;
static HANDLE handle;							//接受消息的线程
static HANDLE Rec_handle;						//接受用户发送消息
static HANDLE Send_handle;						//发送消息给全部用户
static IpInfo m_ipinfo;							//接收信息时创建线程时传输信息
static IpInfo rec_ipinfo;						//接受客户端信息
static SendAllInfo send_Msg_all;				//把消息送到所以用户
ClSocket *UserList;								//登录的用户的sock和线程信息
bool IsStartSer = false;						//判断服务器是否开启
bool IsChartExt = false;						//判断聊天窗口是否弹出
HWND Charthwnd;									//聊天窗口的句柄
HWND Listhwnd;									//用户登录信息列表
SYSTEMTIME Time;								//本地系统时间

BOOL WINAPI Main_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
        HANDLE_MSG(hWnd, WM_INITDIALOG, Main_OnInitDialog);
        HANDLE_MSG(hWnd, WM_COMMAND, Main_OnCommand);
		HANDLE_MSG(hWnd,WM_CLOSE, Main_OnClose);
		case WM_MYMESSAGE:
		{
			if(lParam == WM_LBUTTONDOWN)
			{//在托盘图标上左击
				ShowWindow(hWnd,SW_SHOW);
			}
			else if(lParam == WM_RBUTTONDOWN)
			{//在托盘图标上右击
				MessageBox(NULL,TEXT("托盘来消息了,右键"),TEXT("消息"),MB_OK);
			}
		}
		break;
    }
    return FALSE;
}
BOOL Main_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
	//设置图标的
	HICON hIcon = LoadIcon((HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE) ,MAKEINTRESOURCE(IDI_ICON));
    SendMessage(hwnd, WM_SETICON, TRUE,  (LPARAM)hIcon);
    SendMessage(hwnd, WM_SETICON, FALSE, (LPARAM)hIcon);
	SetWindowText(hwnd,TEXT("昆河 聊天服务器1.0"));
	//初始化Socket库
	WSAStartup(MAKEWORD(2,0),&wsaData);
	gethostname(HostName,sizeof(HostName)/sizeof(TCHAR));
	SetDlgItemText(hwnd,IDC_SERVERNAME,HostName);
	Mhost = gethostbyname(HostName);
	SetDlgItemText(hwnd,IDC_IPADDRESSIP,inet_ntoa(*(struct in_addr*)(Mhost->h_addr)));
	SetDlgItemText(hwnd,IDC_EDITPORT,TEXT("5566"));
	InitLVColumn(hwnd);
	UserList = (ClSocket*)malloc(sizeof(ClSocket));
	UserList->next =NULL;
	send_Msg_all.SockList = UserList;
	send_Msg_all.hwnd = hwnd;
	Charthwnd = GetDlgItem(hwnd,IDC_RICHEDITSCREEN);
	Listhwnd = GetDlgItem(hwnd,IDC_LISTUSER);
	Minimized(hwnd,0);
	SetDlgItemText(hwnd,IDC_RICHEDITSCREEN,TEXT("/t**************服务器初始化成功**************"));
	//EnableMenuItem(GetMenu(hwnd),IDC_BUTTONCHART,MF_DISABLED);//使停止菜单变灰 
    return TRUE;
}
void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
    switch(id)
    {
        case IDC_OK:
		{
			if(!IsStartSer)
			{
				if(InitSocket(hwnd))
				{
					m_ipinfo.sock = sock;
					m_ipinfo.hwnd = hwnd;
					handle = CreateThread(NULL,0,AgreeNewUser,&m_ipinfo,0,NULL);
					CloseHandle(handle);//关闭线程。          但实际不是停止进程
					CreatSocket(hwnd);
					UserList->handle = handle;
					UserList->Sock = sock;
					IsStartSer = true;
					break;
				}
			}
			else 
			{
				MessageBox(NULL,TEXT("服务器已经开启"),TEXT("ERROR"),MB_OK|MB_ICONHAND);
			}
		}
        break;
		case IDC_BUTTONCHARTALL:
		{
			if(IsStartSer)
			{
				if(IsChartExt)
				{
					ShowWindow(Charthwnd,SW_HIDE);
					ShowWindow(Listhwnd,SW_SHOW);
					SetDlgItemText(hwnd,IDC_BUTTONCHARTALL,TEXT("广播消息"));
					IsChartExt = false;
				}
				else
				{
					ShowWindow(Charthwnd,SW_SHOW);
					ShowWindow(Listhwnd,SW_HIDE);
					SetDlgItemText(hwnd,IDC_BUTTONCHARTALL,TEXT("登录信息"));
					IsChartExt = true;
				}
			}
		}
		break;
		case IDC_POWEROFF:
			{
				int IsClose = MessageBox(hwnd,TEXT("真的关闭服务器?"),TEXT("提醒"),MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2);
				if(IDYES==IsClose)
				{
					Minimized(hwnd,1);
					EndDialog(hwnd, 0);
				}
			}
		break;
		case IDC_SEND:
			{
				if(!IsStartSer)
				{
					MessageBox(hwnd,TEXT("服务器没有开启!!!"),TEXT("ERROR"),MB_OK|MB_ICONHAND);
					break;
				}
				TCHAR Msg[255];
				ZeroMemory(Msg,sizeof(Msg)/sizeof(TCHAR));
				GetDlgItemText(hwnd,IDC_RICHEDITIN,Msg,sizeof(Msg)/sizeof(TCHAR));
				int length=lstrlen(Msg);
				if(0==length)
				{
					MessageBox(NULL,TEXT("不能发送空信息"),TEXT("ERROR"),MB_OK|MB_ICONHAND);
					break;
				}
				else if(length > 200)
				{
					MessageBox(hwnd,TEXT("消息太长/t请删除一部分再发送"),TEXT("提醒"),MB_OK|MB_ICONWARNING);
					break;
				}
				TCHAR SendMsg[255];
				ZeroMemory(SendMsg,sizeof(SendMsg)/sizeof(TCHAR));
				ZeroMemory(send_Msg_all.Msg,sizeof(send_Msg_all.Msg)/sizeof(TCHAR));   //不能放在前面哦!!
				lstrcpy(SendMsg,TEXT("服务器管理员:/n "));
				lstrcat(SendMsg,Msg);
				lstrcpy(send_Msg_all.Msg,SendMsg);
				Send_handle = CreateThread(NULL,0,PubMessagetoAll,&send_Msg_all,0,NULL);
				CloseHandle(Send_handle);//关闭线程。          但实际不是停止进程
				//FreshScream(hwnd,SendMsg);
				SetDlgItemText(hwnd,IDC_RICHEDITIN,TEXT(""));
			}
		break;
		case IDC_CLEARN:
			{
				SetDlgItemText(hwnd,IDC_RICHEDITIN,TEXT(""));
			}
		break;
        default:
		break;
    }
}
void Main_OnClose(HWND hwnd)
{
	int IsMin = MessageBox(hwnd,TEXT("最小化到托盘?"),TEXT("提醒"),MB_YESNO|MB_ICONQUESTION);
	if(IDYES==IsMin)
	{
		ShowWindow(hwnd,SW_HIDE);//隐藏窗口
		return;
	}
	Minimized(hwnd,1);
    EndDialog(hwnd, 0);
}
调试用报错
void ShowError()
{
	TCHAR* lpMsgBuf;
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| //自动分配消息缓冲区
	FORMAT_MESSAGE_FROM_SYSTEM, //从系统获取信息
	NULL,GetLastError(), //获取错误信息标识
	MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),//使用系统缺省语言
	(LPTSTR)&lpMsgBuf, //消息缓冲区
	0,
	NULL);
	MessageBox(NULL,lpMsgBuf,"",MB_ICONERROR); 
}
///初始化导线
bool InitSocket(HWND hwnd)
{
	int count = 0;   //标记port冲突的次数,假设超过100次,默认为非端口原因造成无法绑定!!!
	//创建一根电线
	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(INVALID_SOCKET == sock)
	{
		MessageBox(hwnd,TEXT("创建套接字失败!"),TEXT("失败"),MB_OK);
		WSACleanup();
		return false;
	}
	sa.sin_family=AF_INET;
	sa.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	//sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	//设置电线连接服务器端的端口
	//sa.sin_port = htons(IPPORT_TELNET);
	GetDlgItemText(hwnd,IDC_EDITPORT,PORT,sizeof(PORT)/sizeof(TCHAR));
	sa.sin_port = atoi(PORT);
	
	while(SOCKET_ERROR == bind(sock,(SOCKADDR*)&sa,sizeof(sa)))
	{
		sa.sin_port++;
		if(++count>100)
		{
			break;
		}
	}
	if(count>100)
	{
		MessageBox(hwnd,TEXT("绑定套接字失败,无法启动网络/n检查网络在后再登陆!"),
                  TEXT("网络失败"),MB_OK | MB_ICONSTOP);
		closesocket(sock);
		return false;
	}
	TCHAR buff_port[6];
	itoa(sa.sin_port,buff_port,10);
	SetDlgItemText(hwnd,IDC_EDITPORT,buff_port);
	return true;
	//为什么不用设置客户端的端口,难道不需要客户端的端口吗?
}
///回应用户登录到服务器
DWORD WINAPI AgreeNewUser(LPVOID lp)
{
	SOCKET server = ((IpInfo*)lp)->sock;
    HWND hwnd = ((IpInfo*)lp)->hwnd;
	rec_ipinfo.hwnd = hwnd;						//接受信息句柄
	if(SOCKET_ERROR == listen(sock,5))
	{
		ShowError();
		MessageBox(hwnd,TEXT("监听失败!"),TEXT("ERROR"),MB_OK|MB_ICONHAND);
		return 0;
	}
	SOCKET t;
	SOCKADDR_IN ta;
	int ta_len;
	ta_len=sizeof(ta);
	TCHAR RecMsg[255];
	while(1)
	{
		t=accept(server,(SOCKADDR*)&ta,&ta_len);
		if(t==INVALID_SOCKET)
		{
			MessageBox(hwnd,TEXT("不能确立连接"),TEXT("ERROR"),MB_OK|MB_ICONHAND);
			continue;
		}
		ZeroMemory(RecMsg,sizeof(RecMsg)/sizeof(TCHAR));
		recv(t,RecMsg,sizeof(RecMsg)/sizeof(TCHAR),0);
		TCHAR* Load_IP;
		Load_IP = inet_ntoa(ta.sin_addr);
		InsertRecord(hwnd,ta.sin_port,Load_IP,RecMsg);
		
		rec_ipinfo.sock = t;
		Rec_handle = CreateThread(NULL,0,RecvMessage,&rec_ipinfo,0,NULL);
		CloseHandle(Rec_handle);//关闭线程。          但实际不是停止进程
		AddUserSock(UserList,t,Rec_handle);
    }
	return 1;
}
//接受用户发送到服务器的信息并发送给所以用户
DWORD WINAPI RecvMessage(LPVOID lp)
{
	SOCKET client = ((IpInfo*)lp)->sock;
    HWND hwnd = ((IpInfo*)lp)->hwnd;
	//HANDLE Rec_handle;
	TCHAR Msg[50] = "/t/t*********欢迎登录服务器!***********";
	if(SOCKET_ERROR == send(client,Msg,sizeof(Msg)/sizeof(TCHAR),0))
	{
		MessageBox(hwnd,TEXT("不能发送消息"),TEXT("ERROR"),MB_OK|MB_ICONHAND);
	}
	TCHAR RecMsg[256];
	while(1)
	{
		ZeroMemory(RecMsg,sizeof(RecMsg)/sizeof(TCHAR));
		if(SOCKET_ERROR==recv(client,RecMsg,sizeof(RecMsg)/sizeof(TCHAR),0))
		{
			//ListView_FindItem(hwnd,-1,2);
			DelUserSock(UserList,client);
			return 0;
		}
		/把消息发送到每一个用户
		ZeroMemory(send_Msg_all.Msg,sizeof(send_Msg_all.Msg)/sizeof(TCHAR));   //不能放在前面哦!!
		lstrcpy(send_Msg_all.Msg,RecMsg);
		Send_handle = CreateThread(NULL,0,PubMessagetoAll,&send_Msg_all,0,NULL);
		CloseHandle(Send_handle);//关闭线程。          但实际不是停止进程
	}
}
/把信息像所有sock用户表的人发送
DWORD WINAPI PubMessagetoAll(LPVOID lp)
{
	ClSocket* ClientList = ((SendAllInfo*)lp)->SockList;
    HWND hwnd = ((SendAllInfo*)lp)->hwnd;
	((SendAllInfo*)lp)->Msg[200] = '/0';
	GetLocalTime(&Time);
	TCHAR MsgAll[255];
	ZeroMemory(MsgAll,sizeof(MsgAll)/sizeof(TCHAR));
	wsprintf(MsgAll," <%d:%d:%d> %s",Time.wHour,Time.wMinute,Time.wSecond,((SendAllInfo*)lp)->Msg);
	while(ClientList->next!=NULL)
	{
		ClientList = ClientList->next;
		send(ClientList->Sock,MsgAll,255,0);
	}
	FreshScream(hwnd,MsgAll);
	return 1;
}
///初始化LISTVIEW控件
void InitLVColumn(HWND hwnd)
{ 
	LVCOLUMN lvColumn;
	//LVITEM lvItem;
	MyLVColumn MyColumn[3] = {{TEXT("姓名"),0x80,LVCFMT_CENTER},
							{TEXT("端口"),0x60,LVCFMT_CENTER},
							{TEXT("IP地址"),0x98,LVCFMT_CENTER}};
	lvColumn.mask = LVCF_TEXT|LVCF_FMT|LVCF_WIDTH|LVCF_SUBITEM;
	for(int i = 0;i < 3;i++)
	{
		lvColumn.pszText = MyColumn[i].szColumnName;
		lvColumn.fmt = MyColumn[i].fmt;
		lvColumn.cx = MyColumn[i].cx;
		SendDlgItemMessage(hwnd,IDC_LISTUSER,LVM_INSERTCOLUMN,i,(LPARAM)&lvColumn);
	}	
}

///把用户的登录信息插入到listview
void InsertRecord(HWND hwnd,int chPort,TCHAR *chIp,TCHAR *chName )
{//插入记录
	LVITEM lvItem;
	ZeroMemory(&lvItem,sizeof(lvItem));				//初始化0
	int ItemCount = ListView_GetItemCount(GetDlgItem(hwnd,IDC_LISTUSER));  //得到数据总条数
	lvItem.mask = LVIF_TEXT;
	lvItem.iItem = ItemCount;
	lvItem.iSubItem = 0;
	lvItem.pszText = chName;
	//输出 姓名 
	SendDlgItemMessage(hwnd,IDC_LISTUSER,LVM_INSERTITEM,0,(LPARAM)&lvItem);
	lvItem.iSubItem = 1;
	lvItem.mask = LVIF_TEXT;
	TCHAR buff[8];
	ZeroMemory(buff,sizeof(buff)/sizeof(TCHAR));				//初始化0
	itoa(chPort,buff,10);
	lvItem.pszText = buff;
	//输出 端口
	SendDlgItemMessage(hwnd,IDC_LISTUSER,LVM_SETITEM,0,(LPARAM)&lvItem);
	lvItem.iSubItem = 2;
	lvItem.pszText = chIp;
	lvItem.mask = LVIF_TEXT;
	//输出 IP
	SendDlgItemMessage(hwnd,IDC_LISTUSER,LVM_SETITEM,0,(LPARAM)&lvItem);
	PostMessage(GetDlgItem(hwnd,IDC_LISTUSER),WM_VSCROLL, SB_BOTTOM,0);  //屏幕使起始终在最后一行
}
//创建一个socket 接受用户通过UDP发送到本端口的信息
bool CreatSocket(HWND hwnd)
{
	//创建一根电线
	c_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if(INVALID_SOCKET == c_sock)
	{
		MessageBox(hwnd,TEXT("创建套接字失败!"),TEXT("失败"),MB_OK);
		WSACleanup();
		return false;
	}
	AdIp.sin_family=AF_INET;
	AdIp.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	//AdIp.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	//设置电线连接服务器端的端口
	AdIp.sin_port = sa.sin_port;
	if(SOCKET_ERROR == bind(c_sock,(SOCKADDR*)&AdIp,sizeof(AdIp)))
	{
		MessageBox(hwnd,TEXT("绑定套接字失败,无法启动网络/n检查网络在后再登陆!"),
                  TEXT("网络失败"),MB_OK | MB_ICONSTOP);
		closesocket(c_sock);
		WSACleanup();
		return false;
	}
	return true;
}
/向用户列表中加用户数据
void AddUserSock(ClSocket* UserList,SOCKET addsock,HANDLE addhandle)
{
	ClSocket* addpoint;
	addpoint = (ClSocket*)malloc(sizeof(ClSocket));
	addpoint->handle = addhandle;
	addpoint->Sock = addsock;
	addpoint->next = NULL;
	ClSocket* ptr;
	ptr = UserList;
	while(ptr->next != NULL)
	{
		ptr = ptr->next;
	}
	ptr->next = addpoint;
}
//从sock表删除离线用户
void DelUserSock(ClSocket* UserList,SOCKET delsock)
{
	ClSocket* ptr,*pfro;
	pfro = ptr = UserList;
	while(ptr->next != NULL)
	{
		ptr = ptr->next;
		if(ptr->Sock==delsock)
		{
			pfro->next=ptr->next;
			free(ptr);
			return;
		}
		pfro = pfro->next;
	}
	if(pfro->next==NULL)
	{
		//MessageBox(NULL,"123","123",MB_OK);
	}
}
/刷屏
void FreshScream(HWND hwnd,TCHAR *Msg)
{
	TCHAR buff[0x1002];
	ZeroMemory(buff,sizeof(buff)/sizeof(TCHAR));
	GetDlgItemText(hwnd,IDC_RICHEDITSCREEN,buff,sizeof(buff)/sizeof(TCHAR));
	if(lstrlen(buff)>0x1002-256)
	{
		TCHAR swapbuff[0x1002];
		lstrcpy(swapbuff,buff+1000);
		ZeroMemory(buff,sizeof(buff)/sizeof(TCHAR));
		lstrcpy(buff,swapbuff);
	}
	lstrcat((char*)buff,"/n");
	lstrcat((char*)buff,(char*)Msg);
	SetDlgItemText(hwnd,IDC_RICHEDITSCREEN,buff);
	PostMessage(GetDlgItem(hwnd,IDC_RICHEDITSCREEN),WM_VSCROLL, SB_BOTTOM,0);  //屏幕使起始终在最后一行
}
///最小化到托盘
void Minimized(HWND hwnd,int flag)
{
	NOTIFYICONDATA nid;
	nid.cbSize = (DWORD)sizeof(NOTIFYICONDATA);
	nid.hWnd = hwnd;
	nid.uID = IDI_ICON;
	nid.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
	nid.uCallbackMessage = WM_MYMESSAGE;//自定义消息
	HINSTANCE hin = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);//获得程序句柄
	nid.hIcon = LoadIcon(hin,MAKEINTRESOURCE(IDI_ICON));
	lstrcpy(nid.szTip,TEXT("HK 聊天服务器"));
	switch(flag)
	{
	case 0:
		{//添加托盘图标
			Shell_NotifyIcon(NIM_ADD,&nid);
			//ShowWindow(hwnd,SW_HIDE);//隐藏窗口
		}
		break;
	case 1:
		{//删除托盘图标
			Shell_NotifyIcon(NIM_DELETE,&nid);
		}
		break;
	default:
		break;
	}	
}

代码问题和软件问题欢迎交流