您的位置:首页 > 理论基础 > 计算机网络

Scoket 多线程范例 TCP UDP Server Client

2016-06-01 13:55 471 查看
来源: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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: