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