socket TCP 通信
SOCKET可用于主机间或者进程间通信等。
TCP/UDP通信流程:
代码(本机TCP):
Server:
//启动监听线程
void CSocketDlg::OnBnClickedStart()
{
m_run = TRUE;
if (!AfxBeginThread(CSocketDlg::StartRecvThread, this, THREAD_PRIORITY_ABOVE_NORMAL))
{
OutputDebugString("func:AfxBeginThread StartRecvThread failed");
return;
}
}
//停止监听线程
void CSocketDlg::OnBnClickedStop()
{
m_run = FALSE;
SOCKADDR_IN addr;
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(8101);
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);//因为accept阻塞的,这样能够正常退出监听线程
CString msg;
connect(sock, (SOCKADDR*)&addr, sizeof(SOCKADDR));
closesocket(sock);
}
//监听线程
UINT CSocketDlg::StartRecvThread(LPVOID para)
{
//创建套接字
WORD myVersionRequest;
WSADATA wsaData;
myVersionRequest = MAKEWORD(2, 2);
int err;
err = WSAStartup(myVersionRequest, &wsaData);
if (err != 0)
{
CString s;
s.Format(_T("func:WSAStartup failed,error:%d"), GetLastError());
OutputDebugString(s);
char cstrNewDosCmd[] = "netsh.exe winsock reset";
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi;
// 启动进程
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
BOOL bSuc = CreateProcess(NULL, cstrNewDosCmd, NULL, NULL, TRUE, dwCreationFlag, NULL, NULL, &si, &pi);
WaitForSingleObject(pi.hProcess, 5000);
err = WSAStartup(myVersionRequest, &wsaData);
if (err != 0)
return 0;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
CString s;
s.Format(_T("func:WSAStartup version not ok,error:%d"), GetLastError());
OutputDebugString(s);
WSACleanup();
return 0;
}
SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);//创建了可识别套接字
SOCKADDR_IN listenAddr;
listenAddr.sin_family = AF_INET;
listenAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//ip地址
listenAddr.sin_port = htons(8101);//绑定端口
int flag = 1;
int len = sizeof(int);
if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&flag, len) == -1)
{
CString s;
s.Format(_T("set reuse recvSock IP:%s port:%d failed ,error:%d"), inet_ntoa(listenAddr.sin_addr), listenAddr.sin_port, WSAGetLastError());
OutputDebugString(s);
}
if (SOCKET_ERROR == bind(listenSocket, (SOCKADDR*)&listenAddr, sizeof(SOCKADDR)))
{
CString s;
s.Format(_T("bind recvSock IP:%s port:%d failed ,error:%d"), inet_ntoa(listenAddr.sin_addr), listenAddr.sin_port, WSAGetLastError());
OutputDebugString(s);
closesocket(listenSocket);
WSACleanup();
return 0;
}
if (SOCKET_ERROR == listen(listenSocket, 5))
{
CString s;
s.Format(_T("listen recvSock IP:%s port:%d failed ,error:%d"), inet_ntoa(listenAddr.sin_addr), listenAddr.sin_port, WSAGetLastError());
OutputDebugString(s);
closesocket(listenSocket);
WSACleanup();
return 0;
}
OutputDebugString("StartRecvThread OK");
CSocketDlg * pParent = (CSocketDlg *)para;
SOCKADDR_IN clientsocket;
int AddrLen = sizeof(SOCKADDR);
TCHAR recvBuf[4096];
while (pParent->m_run)
{
ZeroMemory(recvBuf, 4096);
SOCKET serConn = accept(listenSocket, (SOCKADDR*)&clientsocket, &AddrLen);
if (serConn == INVALID_SOCKET)
{
CString msg;
msg.Format("server sccept error:%d", WSAGetLastError());
OutputDebugString(msg);
continue;
}
OutputDebugString("server StartRecvThread accept");
int recvLen = recv(serConn, recvBuf, 4096, 0);
OutputDebugString(recvBuf);
if (recvLen < 1)
{
CString msg;
msg.Format("server recv error:%d", WSAGetLastError());
OutputDebugString(msg);
closesocket(serConn);//关闭
continue;
}
CString sendText;
pParent->m_editSend.GetWindowText(sendText);
SOCKADDR_IN sendAddr;
sendAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
sendAddr.sin_family = AF_INET;
sendAddr.sin_port = htons(8102);
if (SOCKET_ERROR != send(serConn, sendText, sendText.GetLength(), 0))
{
OutputDebugString("server send ok");
}
else
{
OutputDebugString("server send error");
}
CString text;
pParent->m_edit.GetWindowText(text);
text = text+ "接收到:"+CString(recvBuf)+"\r\n"+"发送:"+sendText+"\r\n";
pParent->m_edit.SetWindowText(text);
pParent->m_edit.LineScroll(pParent->m_edit.GetLineCount() - 1, 0);
closesocket(serConn);//关闭
}
closesocket(listenSocket);
WSACleanup();
OutputDebugString("StartRecvThread STOP");
return 0;
}
Client:
void CSocketClientDlg::OnBnClickedSend()
{//创建套接字
WORD myVersionRequest;
WSADATA wsaData;
myVersionRequest = MAKEWORD(2, 2);
int err;
err = WSAStartup(myVersionRequest, &wsaData);
if (err != 0)
{
CString s;
s.Format(_T("func:WSAStartup failed,error:%d"), GetLastError());
OutputDebugString(s);
char cstrNewDosCmd[] = "netsh.exe winsock reset";
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi;
// 启动进程
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
BOOL bSuc = CreateProcess(NULL, cstrNewDosCmd, NULL, NULL, TRUE, dwCreationFlag, NULL, NULL, &si, &pi);
WaitForSingleObject(pi.hProcess, 5000);
err = WSAStartup(myVersionRequest, &wsaData);
if (err != 0)
return;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
CString s;
s.Format(_T("func:WSAStartup version not ok,error:%d"), GetLastError());
OutputDebugString(s);
WSACleanup();
return;
}
OutputDebugString("CSocketClientDlg StartSendThread OK");
SOCKADDR_IN sendAddr;
sendAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
sendAddr.sin_family = AF_INET;
sendAddr.sin_port = htons(8101);
CString sendText;
m_editSend.GetWindowText(sendText);
SOCKET SendSocket = socket(AF_INET, SOCK_STREAM, 0);//创建了可识别套接字
CString msg;
if (SOCKET_ERROR != connect(SendSocket, (SOCKADDR*)&sendAddr, sizeof(SOCKADDR)))
{
if (SOCKET_ERROR != send(SendSocket, sendText.GetBuffer(), sendText.GetLength(), 0))
{
OutputDebugString("CSocketClientDlg client send ok");
char recvBuf[4096] = { 0 };
if (recv(SendSocket, recvBuf, 4096, 0) > 0)
{
CString recvText;
m_editRecv.GetWindowText(recvText);
recvText = recvText + "client recv: " + CString(recvBuf) + "\r\n";
m_editRecv.SetWindowText(recvText);
m_editRecv.LineScroll(m_editRecv.GetLineCount()-1, 0);//CEdit自动滚动
}
else
{
msg.Format("CSocketClientDlg recv error:%d", WSAGetLastError());
OutputDebugString(msg);
}
}
else
{
msg.Format("CSocketClientDlg StartSendThread send error:%d", WSAGetLastError());
OutputDebugString(msg);
}
}
else
{
msg.Format("CSocketClientDlg connect error:%d", WSAGetLastError());
OutputDebugString(msg);
}
closesocket(SendSocket);
WSACleanup();
return;
}
几个点:
m_editRecv.LineScroll(m_editRecv.GetLineCount()-1, 0);//CEdit自动滚动到最后一行
m_editSend.ShowScrollBar(SB_VERT, TRUE);//CEdit加上垂直滚动条
//accept阻塞,可以链接一下让它退出
SOCKADDR_IN addr;
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(8101);
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
CString msg;
connect(sock, (SOCKADDR*)&addr, sizeof(SOCKADDR));
closesocket(sock);
//有时候WSAStartup失败,可以重试下,或者执行下netsh winsock reset
CString s;
s.Format(_T("func:WSAStartup failed,error:%d"), GetLastError());
OutputDebugString(s);
char cstrNewDosCmd[] = "netsh.exe winsock reset";
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
BOOL bSuc = CreateProcess(NULL, cstrNewDosCmd, NULL, NULL, TRUE, dwCreationFlag, NULL, NULL, &si, &pi);// 启动进程
WaitForSingleObject(pi.hProcess, 5000);
效果:
代码链接:
VS2015工程:http://download.csdn.net/detail/yangyang031213/9893802
https://github.com/yangyang0312/cpp/tree/master/windows/Socket