📄 clientbysocketdlg.cpp
字号:
MessageBox("绑定网卡出错!", "SOCKET", MB_OK);
closesocket(Sock);
return;
}
if ((WSAGetLastError()) == 10013) {
MessageBox("SOCKET建立失败!", "SOCKET", MB_OK);
closesocket(Sock);
return;
}
SOCKADDR_IN sockAddr;
int iLen = sizeof(sockAddr);
//getpeername(m_lClient,(struct sockaddr *)&sockAddr,&iLen);//得到远程IP地址和端口号
getsockname(Sock, (struct sockaddr*)&sockAddr, &iLen);//得到本地的IP地址和端口号
//strAddr = inet_ntoa(sockAddr.sin_addr);//IP
//uIPPort = sockAddr.sin_port; //端口号
SendMessage(NETWORK_LOG, LOG_bind_tcp, htons(sockAddr.sin_port));
//将SeverSock设置为异步非阻塞模式,并为它注册各种网络异步事件
//m_hWnd为应用程序的主对话框或主窗口的句柄
m_ipconn.GetAddress(serv_ip);
//MessageBox(ipTostr(htonl(serv_ip)));
//MessageBox(m_conn_to_port);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(m_conn_to_port);
serv_addr.sin_addr.S_un.S_addr = htonl(serv_ip);
//MessageBox(ipTostr(htonl(serv_ip)));
if(WSAAsyncSelect(Sock, m_hWnd, NETWORK_EVENT, FD_CONNECT) == SOCKET_ERROR){//先注册connect事件,以专心处理连接,连上后再注册其余事件20061126
MessageBox("注册TCP网络异步事件失败!");
closesocket(Sock);
//WSACleanup();
return;
}
SendMessage(NETWORK_LOG, LOG_conn_ing, htonl(serv_ip));
//MessageBox("连接之前!");
connect(Sock, (LPSOCKADDR)&serv_addr, sizeof(serv_addr));//发送连接请求,事件将响应到OnConnect事件
//MessageBox("已发送,等回送!");
//return;
//while(1);//对主窗口来说,消息处理函数与之是兄弟关系,都要用堆栈的,所以,需要退出后才会运行
GetDlgItem(IDC_OPLIST)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);
//MessageBox("连接之后!");
}
void CClientBySocketDlg::OnNetEvent(WPARAM wParam, LPARAM lParam)
{
//调用Winsock API函数,得到网络事件类型
int iEvent = WSAGETSELECTEVENT(lParam);//32是什么事件?好象是断开事件,是的:)20061126
//调用Winsock API函数,得到发生此事件的客户端套接字
SOCKET CurSock = (SOCKET)wParam;
switch(iEvent)
{
case FD_CONNECT: //Connection or multi-point join operation initiated on socket completed
OnConnect(CurSock, lParam != FD_CONNECT);//无错误或重复连接错误都表示成功连接了,在非阻塞模式下就是这样麻烦:(20061123
//若成功连接,lParam返回FD_CONNECT,否则,返回一错误,此错误由WSAGETSELECTEVENT(lParam)处理后结果是FD_CONNECT,可据此知是否成功连接
break;
case FD_CLOSE: //Connection identified by socket has been closed
OnClose(CurSock);
break;
case FD_READ: //Socket ready for reading
OnReceive(CurSock);
break;
case FD_WRITE: //Socket ready for writing
OnSend(CurSock);
break;
default: break;
}
}
void CClientBySocketDlg::OnClose(SOCKET CurSock)//对端Socket断开
{
//结束与服务端的通信,释放相应资源
UpdateData(TRUE);//因为后边要送字符到界面,所以先把界面内容取回变量:)20061122
closesocket(Sock);
MessageBox("TCP连接已断开!");
closesocket(Sock_U);
m_curstat = "远端服务已断开";
UpdateData(FALSE);
SendMessage(NETWORK_LOG, LOG_conn_cls, 0);
OnResum();
}
void CClientBySocketDlg::OnSend(SOCKET CurSock)//可以发送网络数据包了,(意:相应socket可写了)
{
//在给服务端发数据时做相关预处理
//MessageBox("正在发送!");
UpdateData(TRUE);//因为后边要送字符到界面,所以先把界面内容取回变量:)20061122
m_curstat = "发送数据";
UpdateData(FALSE);
if (!gotudp && CurSock == Sock && connected) OnGetudpPort(CurSock);//首先要获取udp端口号
if ((CurSock == Sock_U) && gotudp) {
recvfrom(CurSock, rubsh, sizeof(rubsh), 0, (PSOCKADDR)&rmot_udp_addr, &rmot_udp_addr_len);//将UDP队列清空,因为:有消息到事件尚未注册,所以在此清空是安全的20061126
WSAAsyncSelect(CurSock, m_hWnd, NETWORK_EVENT, FD_READ);//若宣告udp已可写,则才、仅注册消息到达事件20061126
//GetDlgItem(IDC_UDPECHO)->EnableWindow(TRUE);//仅在获得udp端口号情况下才使按udp消息发送钮可用20061126
}
}
void CClientBySocketDlg::OnReceive(SOCKET CurSock)//有网络数据包到达,可以处理
{
//读出网络缓冲区中的数据包
UpdateData(TRUE);//因为后边要送字符到界面,所以先把界面内容取回变量:)20061122
m_curstat = "接收数据";
if ((CurSock == Sock_U) && gotudp && connected) { //收UDP数据仅在远端UDP端口号获得后的情况下
OnReceiveUDP(CurSock);
//recvfrom(CurSock, rubsh, sizeof(rubsh), 0, (PSOCKADDR)&rmot_udp_addr, &rmot_udp_addr_len);
m_curstat = "接收UDP数据";
}
if (CurSock == Sock && connected) {
OnReceiveTCP(CurSock);
recv(CurSock, rubsh, sizeof(rubsh), 0);//为保证兼容性清空SOCKET流剩余缓冲,因为只用了少于10个octet,20061122
m_curstat = "接收TCP数据";
}
UpdateData(FALSE);
}
void CClientBySocketDlg::OnConnect(SOCKET CurSock, int error)//客户端连接请求
{
//建立与服务端的的通信,取得UDP端口号
//MessageBox("正在连接!");
UpdateData(TRUE);//因为后边要送字符到界面,所以先把界面内容取回变量:)20061122
m_curstat = "连接失败";
if (error) {
closesocket(CurSock);
SendMessage(NETWORK_LOG, LOG_conn_ing, 0);
OnResum();
}
else {
/*int i = MAX_TRY;
debug_ret = 0;
test = 0;
while((debug_ret <= 0) && i) {//在非阻塞模式下可能收不到数据,所以要重试MAX_TRY次
debug_ret = connect(Sock, (LPSOCKADDR)&serv_addr, sizeof(serv_addr));
test = WSAGetLastError();
if (test == 10056) break; //非阻塞模式下,似蜻蜓点水,无法获得握手必须的三次会话完成确认(可能已经连上),并非致命错误,Sleep(SLP_TIK)后再连,若上次会话已连上,则WSAGetLastError()会回送10056,即已经连接20061123
Sleep(SLP_TIK);//没连上?休息一会儿:)20061121
if (!--i) {
UpdateData(FALSE);
closesocket(Sock);
SendMessage(NETWORK_LOG, LOG_conn_ing, 0);
return;
}
}*/
m_curstat = "连接成功";
SendMessage(NETWORK_LOG, LOG_conn_suc, htonl(serv_ip));
//SendMessage(NETWORK_LOG, LOG_send_itm, LPARAM(getUDP));//写日志
//GetDlgItem(IDC_TCPTIME)->EnableWindow(TRUE);//连接成功,则功能可用
//GetDlgItem(IDC_DISCONN)->EnableWindow(TRUE);
SendMessage(NETWORK_LOG, 555, 0);
connected = 1;
WSAAsyncSelect(Sock, m_hWnd, NETWORK_EVENT, FD_CLOSE | FD_READ | FD_WRITE);//连接成功才注册:关闭,有消息到,写准备事件,以防止不必要的麻烦,提高效率20061126
OnGotudpPort(CurSock);//设置UDP连接
}
UpdateData(FALSE);
}
void CClientBySocketDlg::OnLogDisp(WPARAM wParam, LPARAM lParam) //日志书写函数
{
UpdateData(TRUE);
int iEvent = int(wParam);
string catlogAdd = "";
char port[BUFFER_SIZE];
char* getITM = (char*)lParam;
switch(iEvent)
{
case LOG_conn_ing: //尝试连接
if (lParam) {
catlogAdd += "正在连接到服务器:";
catlogAdd += ipTostr(ulint(lParam));
catlogAdd += " -> 端口:";
itoa(usint(m_conn_to_port), port, 10);
catlogAdd += port;
}
else {
catlogAdd += "连接失败!请检查地址及端口号并确认存在指定服务";
OnResum();
}
break;
case LOG_conn_suc: //连接成功
catlogAdd += "成功连接到服务器:";
catlogAdd += ipTostr(ulint(lParam));
catlogAdd += " -> 端口:";
//char port[BUFFER_SIZE];
itoa(usint(m_conn_to_port), port, 10);
catlogAdd += port;
m_curstat = "已连接";
UpdateData(FALSE);
break;
case LOG_send_itm: //各类请求
catlogAdd += "发送TCP消息:";
catlogAdd += getITM;
break;
case LOG_send_str: //发送字符串
catlogAdd += "发送UDP消息:";
catlogAdd += getITM;
break;
case LOG_recv_upt: //绑定UDP端口
catlogAdd += "UDP绑定本地网卡端口:";
itoa(usint(lParam), port, 10);
catlogAdd += port;
break;
case LOG_recv_str://接收字符串
catlogAdd += "收到消息";
catlogAdd += *(CString*)lParam;
break;
case LOG_conn_cls: //关闭连接
catlogAdd += "TCP连接已断开!";
break;
case LOG_recv_tim: //同步时间
catlogAdd += "通过TCP获得服务器时间:";
catlogAdd += getITM;
free(getITM); //赋完值后将前面申请的空间释放20061123
break;
case LOG_recv_udp: //取得正确UDP回送
itoa(ntohs(serv_udp_addr.sin_port), port, 10);
catlogAdd += "通过UDP获得来自:";
catlogAdd += ipTostr(serv_udp_addr.sin_addr.S_un.S_addr);
catlogAdd += ":";
catlogAdd += port;
catlogAdd += " 回送的消息:";
catlogAdd += getITM;
break;
case LOG_bind_tcp: //绑定TCP端口
catlogAdd += "TCP绑定本地网卡端口:";
itoa(usint(lParam), port, 10);
catlogAdd += port;
break;
case LOG_noto_udp: //发送udp消息失败
itoa(ntohs(serv_udp_addr.sin_port), port, 10);
catlogAdd += "通过UDP发送消息到:";
catlogAdd += ipTostr(serv_udp_addr.sin_addr.S_un.S_addr);
catlogAdd += ":";
catlogAdd += port;
catlogAdd += " 失败(远端可能没有启动服务)";
//catlogAdd += getITM;
break;
case LOG_recv_tcp: //=取得tcp消息
itoa(ntohs(serv_addr.sin_port), port, 10);
catlogAdd += "通过TCP获得来自:";
catlogAdd += ipTostr(serv_addr.sin_addr.S_un.S_addr);
catlogAdd += ":";
catlogAdd += port;
catlogAdd += " 的消息:";
catlogAdd += *(CString*)getITM;
break;
case LOG_recv_cal: //=取得tcp消息
//itoa(ntohs(serv_addr.sin_port), port, 10);
catlogAdd += "通过TCP获得消息:";
//catlogAdd += ipTostr(serv_addr.sin_addr.S_un.S_addr);
//catlogAdd += ":";
//catlogAdd += port;
//catlogAdd += " 的消息:";
catlogAdd += getITM;
break;
case LOG_loca_log: //本地日志
catlogAdd += "本地日志:";
catlogAdd += *(CString*)getITM;
break;
default: break;
}
m_curlog = catlogAdd.c_str();
UpdateData(FALSE);
catlogAdd += "\r\n";
m_catlog.SetSel(m_catlog_txt.GetLength(), m_catlog_txt.GetLength(), 0);//光标选择最尾
m_catlog.ReplaceSel(catlogAdd.c_str());
UpdateData(TRUE);
m_catlog.PostMessage(WM_VSCROLL, SB_BOTTOM, 0);//自动滚动到日志最后
}
void CClientBySocketDlg::On_Disconn()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
closesocket(Sock);//强行断开连接?复位?如何温和地断开呢?一定要由服务器来close吗?20061122
closesocket(Sock_U);
m_curstat = "断开连接";
UpdateData(FALSE);
SendMessage(NETWORK_LOG, 555, 0);
OnResum();
}
void CClientBySocketDlg::OnResum()//中断恢复
{
gettime = 0;
getudp = 0;
gotudp = 0;
connected = 0;
//GetDlgItem(IDC_DISCONN)->EnableWindow(FALSE);
//GetDlgItem(IDC_TCPTIME)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
GetDlgItem(IDC_UDPTXT)->EnableWindow(FALSE);
GetDlgItem(IDC_OPLIST)->EnableWindow(FALSE);
GetDlgItem(ID_CONN)->EnableWindow(TRUE);
GetDlgItem(IDC_IPLIST)->EnableWindow(TRUE);
GetDlgItem(IDC_IPCONN)->EnableWindow(TRUE);
GetDlgItem(IDC_PORT)->EnableWindow(TRUE);
}
void CClientBySocketDlg::On_Close()
{
// TODO: Add your control notification handler code here
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -