客户端://连接服务器端
void CChat_TCPClientDlg::OnButtonConnnet()
{
m_socket = socket(AF_INET,SOCK_STREAM,0);
int retconnect;
unsigned short temport;
UpdateData(TRUE);//刷新控件的值到变量上,刷新端口号
temport = (unsigned short)m_ClientPort;
DWORD dwIP;
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))->GetAddress(dwIP);
sockaddr_in addrTo;
addrTo.sin_addr.S_un.S_addr = htonl(dwIP);
addrTo.sin_family = AF_INET;
addrTo.sin_port = htons(temport);
retconnect = connect(m_socket,(sockaddr*)&addrTo,sizeof(sockaddr));
if(SOCKET_ERROR == retconnect)
{
SetDlgItemText(IDC_EDIT_STATE,"连接失败");
return;
}
else
SetDlgItemText(IDC_EDIT_STATE,"连接成功");
CButton *pButton=(CButton*)GetDlgItem(IDC_BUTTON_CONNNET);
pButton->EnableWindow(FALSE);
pButton=(CButton*)GetDlgItem(IDC_BUTTON_OUT);
pButton->EnableWindow(TRUE);
pButton=(CButton*)GetDlgItem(IDC_BUTTON_SEND);
pButton->EnableWindow(TRUE);
pButton=(CButton*)GetDlgItem(IDC_BUTTON_CLEAR);
pButton->EnableWindow(TRUE);
GetDlgItemText(IDC_EDIT_USERNAME,username);
char NewMember[200];
CTime tm=CTime::GetCurrentTime();
CString str=tm.Format("%Y-%m-%d %H:%M:%S");
sprintf(NewMember,"%s--->进入聊天室 %s",username,str);
send(m_socket,NewMember,sizeof(NewMember),0);
HANDLE thread;
thread=CreateThread(NULL,0,RecvProc,NULL,0,NULL);
CloseHandle(thread);
}
DWORD WINAPI CChat_TCPClientDlg::RecvProc(LPVOID lpParameter)
{
CChat_TCPClientDlg* pDlg = (CChat_TCPClientDlg*)(::AfxGetApp()->GetMainWnd());
SOCKET ClientSocket;
ClientSocket = pDlg->m_socket;
HWND hwnd = pDlg->m_hWnd;
int retrecv=0;
char recvbuf[1024];
while(1)
{
memset(recvbuf,0,sizeof(recvbuf));
retrecv = recv(ClientSocket,recvbuf,1024,0);
if(SOCKET_ERROR == retrecv)
{
::SetDlgItemText(hwnd,IDC_EDIT_STATE,"连接断开");
break;
}
else
{
pDlg->m_ListRecv.AddString(recvbuf);
pDlg->m_ListRecv.SetHorizontalExtent(10000);
}
}
return 0;
}
void CChat_TCPClientDlg::OnButtonSend()
{
// TODO: Add your control notification handler code here
CString tempSend;
char strSend[300];
GetDlgItemText(IDC_EDIT_SEND,tempSend);
GetDlgItemText(IDC_EDIT_USERNAME,username);
sprintf(strSend,"%s说: %s",username,tempSend);
int retsend;
retsend = send(m_socket,strSend,strlen(strSend)+1,0);
if(retsend==SOCKET_ERROR)
{
CButton pButton=(CButton)GetDlgItem(IDC_BUTTON_OUT);
pButton->EnableWindow(FALSE);
pButton=(CButton*)GetDlgItem(IDC_BUTTON_SEND);
pButton->EnableWindow(FALSE);
pButton=(CButton*)GetDlgItem(IDC_BUTTON_CLEAR);
pButton->EnableWindow(FALSE);
pButton=(CButton*)GetDlgItem(IDC_BUTTON_CONNNET);
pButton->EnableWindow(TRUE);
SetDlgItemText(IDC_EDIT_STATE,"连接断开");
}
else
{
SetDlgItemText(IDC_EDIT_SEND,"");
}
}
void CChat_TCPClientDlg::OnButtonOut()
{
// TODO: Add your control notification handler code here
/* GetDlgItemText(IDC_EDIT_USERNAME,username);
char leavechar[50];
sprintf(leavechar,"%s<---离开聊天室",username);
send(m_socket,leavechar,sizeof(leavechar),0);*/
closesocket(m_socket);
SetDlgItemText(IDC_EDIT_STATE,"没有连接");
CButton *pButton=(CButton*)GetDlgItem(IDC_BUTTON_CONNNET);
pButton->EnableWindow(TRUE);
pButton=(CButton*)GetDlgItem(IDC_BUTTON_OUT);
pButton->EnableWindow(FALSE);
pButton=(CButton*)GetDlgItem(IDC_BUTTON_SEND);
pButton->EnableWindow(FALSE);
pButton=(CButton*)GetDlgItem(IDC_BUTTON_CLEAR);
pButton->EnableWindow(FALSE);
}
void CChat_TCPClientDlg::OnButtonClear()
{
// TODO: Add your control notification handler code here
m_ListRecv.ResetContent();
}
服务器:
// the minimized window.
HCURSOR CChat_TCPSrvDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
BOOL CChat_TCPSrvDlg::InitSocket(unsigned short port)
{
//初始化连接套接字
ClientTotal = 0;
for(int i=0;i<20;i++)
{
ClientSocket[i] = 0;
ClientAddr[i] = "";
}
//创建绑定监听套接字
m_socket = socket(AF_INET,SOCK_STREAM,0);
if(INVALID_SOCKET==m_socket)
{
SysStr = "创建socket失败";
m_SysMsg.AddString(SysStr);
return FALSE;
}
else
{
SysStr = "创建socket成功";
m_SysMsg.AddString(SysStr);
m_SysMsg.SetHorizontalExtent(1000);
}
//地址族赋值
sockaddr_in addrsock;
addrsock.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrsock.sin_family = AF_INET;
addrsock.sin_port = htons(port);
//绑定套接字
int retbind;
retbind = bind(m_socket,(SOCKADDR*)&addrsock,sizeof(SOCKADDR));
if(SOCKET_ERROR==retbind)
{
closesocket(m_socket);
SysStr = "bind 失败";
m_SysMsg.AddString(SysStr);
SysStr = "启动失败";
m_SysMsg.AddString(SysStr);
return FALSE;
}
else
{
SysStr = "bind成功";
m_SysMsg.AddString(SysStr);
}
//设置监听模式
if(listen(m_socket,20)!=0)
{
SysStr = "启动失败";
m_SysMsg.AddString(SysStr);
return FALSE;
}
else
{
SysStr = "服务器启动成功";
m_SysMsg.AddString(SysStr);
}
return TRUE;
}
//启动服务器
void CChat_TCPSrvDlg::OnButtonStart()
{
// TODO: Add your control notification handler code here
SrvState = TRUE;
ClientTotal = 0;
unsigned short temport;
BOOL InitSock;
UpdateData(TRUE);
temport = m_Port;
if(temport>=1025 && temport<=9999)
{
InitSock = InitSocket(temport); //调用初始化套接字
//让“启动按钮”不可用,和让“关闭按钮”可用
CButton *pButton=(CButton*)GetDlgItem(IDC_BUTTON_CLOSE);
pButton->EnableWindow();
pButton=(CButton*)GetDlgItem(IDC_BUTTON_START);
pButton->EnableWindow(FALSE);
//创建一级线程,用于监听用户的连接
HANDLE hThread=CreateThread(NULL,0,AcceptClient,NULL,0,NULL);
CloseHandle(hThread);
}
else
{
SysStr="端口号不在使用范围内,启动失败";
m_SysMsg.AddString(SysStr);
m_SysMsg.SetHorizontalExtent(1000);
}
hMutex = CreateMutex(NULL,FALSE,NULL);
}
//一级线程,连接客户请求
DWORD WINAPI CChat_TCPSrvDlg::AcceptClient(LPVOID lpParameter)
{
CChat_TCPSrvDlg* pDlg = (CChat_TCPSrvDlg*)(::AfxGetApp()->GetMainWnd());
SOCKET socketacp = pDlg->m_socket;
sockaddr_in addrClient;
int len = sizeof(sockaddr);
while(pDlg->SrvState)
{
pDlg->ClientSocket[pDlg->ClientTotal]=accept(socketacp,(SOCKADDR *)&addrClient,&len);
WaitForSingleObject(pDlg->hMutex,INFINITE);
pDlg->ClientTotal++;
pDlg->SysStr = "新用户加入";
pDlg->m_SysMsg.AddString(pDlg->SysStr);
ReleaseMutex(pDlg->hMutex);
if(pDlg->ClientTotal==1) //只是用来启动二级进程,当第二个客户端连接上后,if语句不执行,recv进程一直在执行
{
//创建二级线程,用于接收数据。
HANDLE hThread=CreateThread(NULL,0,RecvProc,NULL,0,NULL);
CloseHandle(hThread);
}
}
return 0;
}
//二级线程,接收用户消息,并显示
DWORD WINAPI CChat_TCPSrvDlg::RecvProc(LPVOID lpParameter)
{
CChat_TCPSrvDlg* pDlg1 = (CChat_TCPSrvDlg*)(::AfxGetApp()->GetMainWnd());
fd_set fsRead;
timeval tm = {0,10000};
char recvBuf[200];
while(pDlg1->SrvState)
{
FD_ZERO(&fsRead);
for(int m=0;m<(pDlg1->ClientTotal);m++) //对所有用户进行select监视
FD_SET((pDlg1->ClientSocket[m]),&fsRead);
int retRead = select(pDlg1->ClientTotal+1,&fsRead,NULL,NULL,&tm);
if(SOCKET_ERROR == retRead)
return 1;
else
{
for(int index=0;index<(pDlg1->ClientTotal);index++)
{
if(FD_ISSET(pDlg1->ClientSocket[index],&fsRead))
{
memset(recvBuf,0,sizeof(recvBuf));
recv(pDlg1->ClientSocket[index],recvBuf,sizeof(recvBuf),0);
if(strlen(recvBuf)==0) //判断用户是否退出
{
pDlg1->SysStr = "有一个用户离开";
pDlg1->m_SysMsg.AddString(pDlg1->SysStr);
pDlg1->ClientSocket[index] = pDlg1->ClientSocket[pDlg1->ClientTotal-1]; //将最后一个放到刚刚退出的client那里去
pDlg1->ClientSocket[pDlg1->ClientTotal-1] = 0; //保证所有未退出的客户端都在前面
if(pDlg1->ClientTotal==0)
return 0;
pDlg1->ClientTotal--;
}
else
{
pDlg1->m_UserMsg.AddString(recvBuf);
pDlg1->m_UserMsg.SetHorizontalExtent(10000);
for(int n=0;n<(pDlg1->ClientTotal);n++)
{
send(pDlg1->ClientSocket[n],recvBuf,sizeof(recvBuf),0);
}
}
}
}
}
}
return 0;
}
//关闭服务器
void CChat_TCPSrvDlg::OnButtonClose()
{
// TODO: Add your control notification handler code here
WaitForSingleObject(hMutex,INFINITE);
SysStr="服务器已关闭";
m_SysMsg.AddString(SysStr);
SrvState = FALSE;
for(int k=0;k<ClientTotal;k++)
send(ClientSocket[k],"服务器已关闭,请断开服务器重新连接",sizeof("服务器已关闭,请断开服务器重新连接")+1,0);
closesocket(m_socket);
while(ClientTotal>0)
{
closesocket(ClientSocket[ClientTotal-1]);
ClientTotal--;
}
CButton *pButton=(CButton*)GetDlgItem(IDC_BUTTON_CLOSE);
pButton->EnableWindow(FALSE);
pButton=(CButton*)GetDlgItem(IDC_BUTTON_START);
pButton->EnableWindow();
}
void CChat_TCPSrvDlg::OnClickedButtonSend()
{
// TODO: 在此添加控件通知处理程序代码
CString tempSend;
char strSend[300];
GetDlgItemText(IDC_EDIT_SEND,tempSend);
sprintf(strSend,"服务器: %s",tempSend);
send(m_socket,strSend,strlen(strSend)+1,0);
m_UserMsg.AddString(strSend);
SetDlgItemText(IDC_EDIT_SEND,"");
}
void CChat_TCPSrvDlg::OnClickedButtonClear()
{
// TODO: 在此添加控件通知处理程序代码
m_UserMsg.ResetContent();
}