关闭

Scoket 多线程范例 TCP UDP Server Client

1119人阅读 评论(0) 收藏 举报

来源:VC驿站


<span style="font-size:14px;">/**********核心使用**********/
SOCKET m_Socket;

/**********TCP Server 接收线程**********/
static UINT __cdecl ThreadProcTCPServer(LPVOID pParam);

UINT CNetworkVideoDlg::ThreadProcTCPServer( LPVOID pParam )
{
	ASSERT(pParam);

	sockaddr_in clientAddr = {0};

	CNetworkVideoDlg *pThis = (CNetworkVideoDlg *)pParam;

	pThis->WinSockInit();

	pThis->m_serverListenSocket = INVALID_SOCKET;
	pThis->m_serverListenSocket = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);

	if ( pThis->m_serverListenSocket == INVALID_SOCKET ) {
		AfxMessageBox(_T("新建Socket失败!"));
		goto __Error_End;
	}

	pThis->configParams();//配置IP地址 端口 等

	sockaddr_in service;
	service.sin_family = AF_INET;
	service.sin_addr.s_addr = INADDR_ANY; //任意本地IP地址
	service.sin_port = htons(pThis->m_localPort);

	if ( bind(pThis->m_serverListenSocket, (sockaddr*)&service, sizeof(sockaddr_in)) == SOCKET_ERROR )
	{
		AfxMessageBox(_T("绑定端口失败!"));
		goto __Error_End;
	}

	if( listen(pThis->m_serverListenSocket, SOMAXCONN) == SOCKET_ERROR ) 
	{
		AfxMessageBox(_T("监听失败!"));
		goto __Error_End;
	}

	int iLen = sizeof(sockaddr_in);

	//等待客户端来链接
	pThis->m_serverSocket = accept(pThis->m_serverListenSocket, (struct sockaddr *)&clientAddr , &iLen); 
	if (pThis->m_serverSocket == INVALID_SOCKET) 
	{
		goto __Error_End;
	}
	else
	{
		CString strState;
		strState.Format(_T("%s 已经上线"),inet_ntoa(clientAddr.sin_addr));
		pThis->SetDlgItemText(IDC_EDIT_STATE, strState);
	}

	while(m_bRunFlag)
	{
		if ( pThis->SOCKET_Select(pThis->m_serverSocket) ) //检测可读性
		{
			TCHAR szBuf[MAX_BUF_SIZE] = {0};
			int iRet = recv(pThis->m_serverSocket, (char *)szBuf, MAX_BUF_SIZE, 0);

			if ( iRet > 0 ) 
			{
				//right;
				pThis->ShowReceiveMsg(szBuf);
			}else{
				//close socket;
				pThis->ShowReceiveMsg(_T("客户端已下线,请重新开启服务器等待客户端连接!"));
				break;
			}
		}
		Sleep(500);
	}

__Error_End:
	if (pThis->m_serverListenSocket != INVALID_SOCKET) {
		closesocket(pThis->m_serverListenSocket);
	}
	if (pThis->m_serverSocket != INVALID_SOCKET) {
		closesocket(pThis->m_serverSocket);
	}
	WSACleanup();

	::PostMessage(pThis->GetSafeHwnd(),MSG_THREAD_SAFE_END,0,0);

	return TRUE;
}

/**********TCP Client 接收线程**********/
static UINT __cdecl ThreadProcTCPClient(LPVOID pParam);


UINT CNetworkVideoDlg::ThreadProcTCPClient( LPVOID pParam )
{
	ASSERT(pParam);

	CNetworkVideoDlg* pThis = (CNetworkVideoDlg*) pParam;

	pThis->WinSockInit();
	
	pThis->m_clientSocket = INVALID_SOCKET;
	pThis->m_clientSocket = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);
	if ( pThis->m_clientSocket == INVALID_SOCKET )
	{
		AfxMessageBox(_T("新建Socket失败!"));
		goto __Error_End;
	}

	pThis->configParams();

	sockaddr_in server;
	server.sin_family = AF_INET;
	server.sin_port = htons(pThis->m_destPort);
	server.sin_addr.s_addr = inet_addr(pThis->m_strIP);//192.168.1.57 "127.0.0.1"

	if ( connect(pThis->m_clientSocket, (struct sockaddr *)&server,  sizeof(struct sockaddr)) == SOCKET_ERROR ) 
	{
		ShowError();
		AfxMessageBox(_T("连接失败,请重试!"));
		goto __Error_End;
	}else
	{
		//pThis->ShowMsg(_T("连接成功!"));
		pThis->SetDlgItemText(IDC_EDIT_STATE,_T("连接成功!"));
	}

	while(m_bRunFlag)
	{
		if ( pThis->SOCKET_Select(pThis->m_clientSocket) ) //检测可读性
		{
			TCHAR szBuf[MAX_BUF_SIZE] = {0};

			int iRet = recv(pThis->m_clientSocket, (char *)szBuf, MAX_BUF_SIZE, 0);
			
			if ( iRet > 0 )//读取正确
			{			
				pThis->ShowReceiveMsg(szBuf);

			}else //连接已经关闭、重启或中断;
			{		
				pThis->ShowReceiveMsg(_T("链接已经中断,请重新进行连接!"));
				break;
			}
		}
		Sleep(500);//存疑 是否需要加???
	}

__Error_End:
	if (pThis->m_clientSocket != INVALID_SOCKET)
	{
		closesocket(pThis->m_clientSocket);
	}
	WSACleanup();

	::PostMessage(pThis->GetSafeHwnd(),MSG_THREAD_SAFE_END,0,0);

	return TRUE;
}

/**********UDP Server 接收线程**********/
static UINT __cdecl ThreadProcUDPServer(LPVOID pParam);


UINT CNetworkVideoDlg::ThreadProcUDPServer( LPVOID pParam )
{
	ASSERT(pParam);

	sockaddr_in clientAddr = {0};

	CNetworkVideoDlg *pThis = (CNetworkVideoDlg *)pParam;

	pThis->WinSockInit();

	pThis->m_serverSocket = INVALID_SOCKET;

	pThis->m_serverSocket = socket(AF_INET , SOCK_DGRAM , 0);

	if ( pThis->m_serverSocket == INVALID_SOCKET )
	{
		AfxMessageBox(_T("新建Socket失败!"));
		goto __Error_End;
	}

	pThis->configParams();

	sockaddr_in service;
	service.sin_family = AF_INET;
	service.sin_addr.s_addr = INADDR_ANY; //任意本地IP地址
	service.sin_port = htons(pThis->m_localPort);

	if ( bind(pThis->m_serverSocket, (sockaddr*)&service, sizeof(sockaddr_in)) == SOCKET_ERROR )
	{
		AfxMessageBox(_T("绑定端口失败!"));
		goto __Error_End;
	}


	while(m_bRunFlag)
	{
		if ( pThis->SOCKET_Select(pThis->m_serverSocket) ) //检测可读性
		{
			TCHAR szBuf[MAX_BUF_SIZE] = {0};
			//int iRet = recv(pThis->m_serverSocket, (char *)szBuf, MAX_BUF_SIZE, 0);

			//char recvBuf[50];

			SOCKADDR addrClient;

			int len = sizeof(SOCKADDR);

			int iRet = recvfrom(pThis->m_serverSocket, (char *)szBuf,MAX_BUF_SIZE,0,(SOCKADDR*)&addrClient,&len);

			if ( iRet > 0 ) //读取正确
			{			
				pThis->ShowReceiveMsg(szBuf);

				sockaddr_in sin;
				memcpy(&sin, &addrClient, sizeof(sin));
				CString strState;
				strState.Format(_T("来自%s的数据"),inet_ntoa(sin.sin_addr));
				pThis->SetDlgItemText(IDC_EDIT_STATE, strState);

			}else
			{
				//close socket;
				pThis->ShowReceiveMsg(_T("recvfrom failed!"));
				break;
			}

		}
		Sleep(500);
	}

__Error_End:
	if (pThis->m_serverSocket != INVALID_SOCKET) 
	{
		closesocket(pThis->m_serverSocket);
	}

	WSACleanup();

	::PostMessage(pThis->GetSafeHwnd(),MSG_THREAD_SAFE_END,0,0);

	return TRUE;
}

/**********UDP Client 接收线程**********/
static UINT __cdecl ThreadProcUDPClient(LPVOID pParam);


UINT CNetworkVideoDlg::ThreadProcUDPClient( LPVOID pParam )
{
	ASSERT(pParam);

	sockaddr_in clientAddr = {0};

	CNetworkVideoDlg *pThis = (CNetworkVideoDlg *)pParam;

	pThis->WinSockInit();

	pThis->m_clientSocket = INVALID_SOCKET;

	pThis->m_clientSocket = socket(AF_INET , SOCK_DGRAM , 0);

	if ( pThis->m_clientSocket == INVALID_SOCKET )
	{
		AfxMessageBox(_T("新建Socket失败!"));
		goto __Error_End;
	}

	pThis->configParams();

	sockaddr_in service;
	service.sin_family = AF_INET;
	service.sin_addr.s_addr = INADDR_ANY; 
	service.sin_port = htons(pThis->m_localPort);

	if ( bind(pThis->m_clientSocket, (sockaddr*)&service, sizeof(sockaddr_in)) == SOCKET_ERROR )
	{
		AfxMessageBox(_T("绑定端口失败!"));
		goto __Error_End;
	}

	while(m_bRunFlag)
	{
		if ( pThis->SOCKET_Select(pThis->m_clientSocket) ) //检测可读性
		{
			TCHAR szBuf[MAX_BUF_SIZE] = {0};
			//int iRet = recv(pThis->m_serverSocket, (char *)szBuf, MAX_BUF_SIZE, 0);

			//char recvBuf[50];

			SOCKADDR addrClient;

			int len = sizeof(SOCKADDR);

			int iRet = recvfrom(pThis->m_clientSocket, (char *)szBuf,MAX_BUF_SIZE,0,(SOCKADDR*)&addrClient,&len);

			if ( iRet > 0 ) //读取正确
			{			
				pThis->ShowReceiveMsg(szBuf);

			}else
			{
				//close socket;
				pThis->ShowReceiveMsg(_T("recvfrom failed!"));
				break;
			}
		}
		Sleep(500);
	}

__Error_End:
	if (pThis->m_clientSocket != INVALID_SOCKET)
	{
		closesocket(pThis->m_clientSocket);
	}

	WSACleanup();

	::PostMessage(pThis->GetSafeHwnd(),MSG_THREAD_SAFE_END,0,0);

	return TRUE;
}


/**********发送范例**********/
void CNetworkVideoDlg::OnBnClickedButtonSend()
{
	if (m_cbTCPUDP.GetCurSel() == 0) //TCP Server
	{	
		CString strText;
		GetDlgItemText(IDC_EDIT_SEND, strText);

		int count = m_listServerSocket.GetCount();
		for (int i = 0; i < count;++i)
		{
			CClientInfo clientInfo = m_listServerSocket.GetAt(m_listServerSocket.FindIndex(i));

			if (!strText.IsEmpty() && SOCKET_Select(clientInfo.m_clientSocket, 100, FALSE)) 
			{
				send(clientInfo.m_clientSocket, (char *)strText.GetBuffer(), strText.GetLength()*sizeof(TCHAR), 0);
				SetDlgItemText(IDC_EDIT_SEND, _T(""));
			}
		}
	}else if (m_cbTCPUDP.GetCurSel() == 1)//TCP Client
	{
		if (m_clientSocket == INVALID_SOCKET)
		{
			AfxMessageBox(_T("请先打开"));
			return;
		}
		CString strText;
		GetDlgItemText(IDC_EDIT_SEND, strText);

		if (!strText.IsEmpty() && SOCKET_Select(m_clientSocket, 100, FALSE)) 
		{
			send(m_clientSocket, (char *)strText.GetBuffer(), strText.GetLength()*sizeof(TCHAR), 0);
			SetDlgItemText(IDC_EDIT_SEND, _T(""));
		}

	}else if (m_cbTCPUDP.GetCurSel() == 2)//UDP Server
	{
		if (m_serverSocket == INVALID_SOCKET)
		{
			AfxMessageBox(_T("请先打开"));
			return;
		}
		CString strText;
		GetDlgItemText(IDC_EDIT_SEND, strText);

		if (!strText.IsEmpty() && SOCKET_Select(m_serverSocket, 100, FALSE)) 
		{
			configParams();

			sockaddr_in destaddr;
			destaddr.sin_family = AF_INET;
			destaddr.sin_addr.s_addr = inet_addr(m_strIP);
			destaddr.sin_port = htons(m_destPort);

			sendto(m_serverSocket, (char *)strText.GetBuffer(), strText.GetLength()*sizeof(TCHAR), 0,
				(struct sockaddr*)&destaddr,sizeof(destaddr));

			SetDlgItemText(IDC_EDIT_SEND, _T(""));
		}

	}else if (m_cbTCPUDP.GetCurSel() == 3)//UDP Client
	{
		if (m_clientSocket == INVALID_SOCKET)
		{
			AfxMessageBox(_T("请先打开"));
			return;
		}
		CString strText;
		GetDlgItemText(IDC_EDIT_SEND, strText);

		if (!strText.IsEmpty() && SOCKET_Select(m_clientSocket, 100, FALSE)) 
		{
			//send(m_clientSocket, (char *)strText.GetBuffer(), strText.GetLength()*sizeof(TCHAR), 0);

			configParams();

			sockaddr_in destaddr;
			destaddr.sin_family = AF_INET;
			destaddr.sin_addr.s_addr = inet_addr(m_strIP);; //任意本地IP地址
			destaddr.sin_port = htons(m_destPort);

			sendto(m_clientSocket, (char *)strText.GetBuffer(), strText.GetLength()*sizeof(TCHAR), 0,
				(struct sockaddr*)&destaddr,sizeof(destaddr));

			SetDlgItemText(IDC_EDIT_SEND, _T(""));
		}
	}

}


/**********辅助函数**********/
  // 完成SOCKET的库的初始化 版本为2.2 最新
  BOOL WinSockInit(void)
  {
    WSADATA data = {0};

    if(WSAStartup(MAKEWORD(2, 2), &data)) //完成SOCKET的库的初始化 版本为2.2 最新
      return FALSE;

    if ( LOBYTE(data.wVersion) !=2 || HIBYTE(data.wVersion) != 2 ){
      WSACleanup();
      return FALSE;
    }
    return TRUE;
  }

  //封装Select函数 ; 参数:1.待查询的SOCKET;2.查询时间毫秒;3.TRUE检测可读性 FALSE检测可写性
  BOOL SOCKET_Select( SOCKET hSocket, int nTimeOut = 100, BOOL bRead = TRUE )
  {
    fd_set fdset;
    timeval tv;

    FD_ZERO(&fdset);
    FD_SET(hSocket, &fdset);

    nTimeOut = nTimeOut > 1000 ? 1000 : nTimeOut; //检测时间时间不超过1秒
    tv.tv_sec  = 0;
    tv.tv_usec = nTimeOut;

    int iRet = 0;
    if ( bRead ) 
    {
      iRet = select(0, &fdset, NULL , NULL, &tv); //检测可读性

    }else
    {
      iRet = select(0, NULL , &fdset, NULL, &tv); //检测可写性

    }

    if(iRet <= 0) //有错误发送 或者 该hSocket不具备可读写性
    {
      return FALSE;

    } else if (FD_ISSET(hSocket, &fdset)) //该hSocket具备可读写性
    {
      return TRUE;
    }
    return FALSE;
  }

 // 将字符串显示到CEdit框的末尾
  void ShowReceiveMsg(CString strMsg)
  {
    m_editReceive.SetSel(-1, -1); //选择最末尾
    m_editReceive.ReplaceSel( strMsg+_T("\r\n")); 
  }

/**********补充说明**********/
  TCP编程的服务器端一般步骤是:
  1、创建一个socket,用函数socket();
  2、设置socket属性,用函数setsockopt(); * 可选
  3、绑定IP地址、端口等信息到socket上,用函数bind();
  4、开启监听,用函数listen();
  5、接收客户端上来的连接,用函数accept();
  6、收发数据,用函数send()和recv(),或者read()和write();
  7、关闭网络连接;
  8、关闭监听;

  TCP编程的客户端一般步骤是:
  1、创建一个socket,用函数socket();
  2、设置socket属性,用函数setsockopt();* 可选
  3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
  4、设置要连接的对方的IP地址和端口等属性;
  5、连接服务器,用函数connect();
  6、收发数据,用函数send()和recv(),或者read()和write();
  7、关闭网络连接;
    
  UDP编程的服务器端一般步骤是:
  1、创建一个socket,用函数socket();
  2、设置socket属性,用函数setsockopt();* 可选
  3、绑定IP地址、端口等信息到socket上,用函数bind();
  4、循环接收数据,用函数recvfrom();
  5、关闭网络连接;

  UDP编程的客户端一般步骤是:
  1、创建一个socket,用函数socket();
  2、设置socket属性,用函数setsockopt();* 可选
  3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
  4、设置对方的IP地址和端口等属性;
  5、发送数据,用函数sendto();
  6、关闭网络连接;
/**********补充说明**********/
   //设置系统接收缓存
  int nRecvBuf = MAX_BUF_SIZE;
  setsockopt(pMP->m_socket,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
</span>

















0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:251390次
    • 积分:4064
    • 等级:
    • 排名:第8049名
    • 原创:101篇
    • 转载:362篇
    • 译文:0篇
    • 评论:14条
    最新评论