/*接收一行数据(以"\n"结尾) 入参:pBuf - 接收缓存 nMaxCount - 一行的最大长度(包括"\n") nMicsec - socket超时值,单位:微妙,缺省:500000微妙 出参:实际接收字节数 ,如果接收失败,返回负数,如果对方关闭,返回0 */ int CTcp::RecvLine_n (void *pBuf, int nMaxCount, int nMicsec) const { assert ((m_nSock != -1) && pBuf && (nMaxCount > 0)); char *ptr = (char *)pBuf; int rn = 0, ret = 0; while (rn < nMaxCount) { if ((ret = Recvn (ptr + rn, 1, nMicsec)) <= 0) return ret; rn++; if ((rn >= 1) && (ptr[rn - 1] == '\n')) break; } return rn; }
DWORD WINAPI Server() { SOCKET sock; DWORD ThreadID; SYSTEM_INFO system_info; struct sockaddr_in addr; int iSize = sizeof(sockaddr_in); server_sock = CreateSocket(LampServerPort, LampServerIpAddress); if (server_sock == INVALID_SOCKET || server_sock == SOCKET_ERROR) { MessageBox(NULL, L"端口被占用", L"Error", MB_OK); beRunning = FALSE; UpdateServerStatus(); return false; } beRunning = true; UpdateServerStatus(); //创建完成端口句柄 completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, null, 0, 0); //创建工作者线程 GetSystemInfo(&system_info); for (UINT i = 0; i < system_info.dwNumberOfProcessors; ++i) { HANDLE ThreadHandle; ThreadHandle = CreateThread(null, 0, LampWorkerThread, completionPort, 0, &ThreadID); CloseHandle(ThreadHandle); } HANDLE hSendLampDataToPCThread = ::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)LampThread, NULL, 0, &ThreadID); if (hSendLampDataToPCThread != 0) { CloseHandle(hSendLampDataToPCThread); //MessageBox(NULL, L"SendLampDataToPCThread启动成功", L"Error", MB_OK); } char buf[40] = {0x00}; while(server_sock != INVALID_SOCKET && beRunning) { sock = ::accept(server_sock, (sockaddr *)&addr, &iSize); if (sock == INVALID_SOCKET) { continue; } //设置socket为非阻塞模式 //int iMode = 1; //ioctlsocket(sock, FIONBIO, (u_long FAR*) &iMode); fd_set fd; struct timeval time_out; FD_ZERO(&fd); FD_SET(sock, &fd); time_out.tv_sec = 20; //设置超时时间为20s time_out.tv_usec = 0; //对于每个新的lamp连接,等待20s接受其发送的消息,若没有收到则关闭连接 int err = select(0, &fd, NULL, NULL, &time_out); if ((err == SOCKET_ERROR) || (err == 0)) { closemysocket(sock); continue; } if (FD_ISSET(sock, &fd)) { //接收标记,区分连接是客户端还是节点 char label[1] = {0x00}; if (Recvn(sock, label, sizeof(label)) < sizeof(label)) { closemysocket(sock); continue; } if ((u_char)label[0] == 0xAA) //客户端连接 { GUID guid; if (S_OK != ::CoCreateGuid(&guid)) //为每个pc端生成唯一id { closemysocket(sock); continue; } PCClient *pc = new PCClient(sock, guid, addr); { MutexGuard guard(PCClientListMutex); PCClientList.push_back(pc); } UpdatePCListView(); HANDLE hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)PCClientThread, (void *)pc, 0, &ThreadID); if (hThread != 0) { CloseHandle(hThread);//MessageBox(NULL, L"PC连接成功", L"Error", MB_OK); } } else if (label[0] == 0x5A) //节点连接 { //接收数据长度和节点ID char len_lampid[3] = {0x00}; if (Recvn(sock, len_lampid, sizeof(len_lampid)) < sizeof(len_lampid)) { closemysocket(sock); continue; } int len = len_lampid[0]; char* data = new char[len + 1]; data[0] = 0x5A; memcpy(data + 1, len_lampid, sizeof(len_lampid)); if (Recvn(sock, data + 4, len - sizeof(len_lampid)) < (int)(len - sizeof(len_lampid))) { closemysocket(sock); continue; } SendDataToPCClient(data, len + 1); delete[] data; u_short lampid = *(u_short*)(len_lampid + 1); //len_lampid[1]和len_lampid[2]表示id的低字节和高字节部分 //检查此lampid是否已经存在列表中 if (citylamp.QueryLampID(lampid)) { closemysocket(sock); continue; } LPLampMutexSockStruct lpLMSS = new LampMutexSockStruct(sock, &addr, lampid, RECV_POSTED); citylamp.SetLampID2LampMutexSockMap(lampid, lpLMSS); UpdateLampListView(true, lampid); //将lampsock绑定到完成端口 /* LPPER_HANDLE_DATA lpPerHandleData = (LPPER_HANDLE_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_HANDLE_DATA)); lpPerHandleData->Socket = sock; memcpy(&lpPerHandleData->ClientAddr, &addr, sizeof(sockaddr_in)); lpPerHandleData->LampID = lampid; CreateIoCompletionPort((HANDLE)sock, completionPort, (DWORD)lpPerHandleData, 0); */ CreateIoCompletionPort((HANDLE)sock, completionPort, (DWORD)lpLMSS->lpPerHandleData, 0); /* LPPER_IO_DATA lpPerIOData = (LPPER_IO_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_DATA)); lpPerIOData->Buffer.len = MAXBUFSIZE; lpPerIOData->Buffer.buf = lpPerIOData->szMessage; lpPerIOData->OperationType = RECV_POSTED; WSARecv(lpPerHandleData->Socket, &lpPerIOData->Buffer, 1, &lpPerIOData->NumberOfBytesTransferred, &lpPerIOData->Flags, &lpPerIOData->Overlapped, null); */ WSARecv(lpLMSS->lpPerHandleData->Socket, &lpLMSS->lpPerIOData->Buffer, 1, &lpLMSS->lpPerIOData->NumberOfBytesTransferred, &lpLMSS->lpPerIOData->Flags, &lpLMSS->lpPerIOData->Overlapped, null); //MessageBox(NULL, L"Lamp连接成功", L"Error", MB_OK); } else { closemysocket(sock); continue; } } } closemysocket(server_sock); WSACleanup(); UpdateServerStatus(); beRunning = FALSE; return 1; }