⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clientbysocketdlg.cpp

📁 自己编写的SOCKET程序 源码有详尽的注释 可以用来学习C/S程序的编写方法
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		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 + -