在看别人的代码,这部分以前是串口传输的,现在改成socket传输了
主界面的OnTimer函数会执行下面的ExcuteCommand函数,
BOOL CComWnd::ExcuteCommand(COneCommand *pCmd) {
  m_bWriting=TRUE;//m_bWriting是用来判断读写是否完成的,在WriteThread中,如果sennd完毕,则m_bWriting=TRUE
  AfxBeginThread(WriteThread,this,THREAD_PRIORITY_NORMAL);
  while(m_bWriting) 
      Sleep(1);     
  if(m_bComError)   
      return FALSE;
  AfxBeginThread(ReadThread,this,THREAD_PRIORITY_NORMAL);
}
上面的代码中,while(m_bWriting)的循环条件能保证主线程一直等待,WriteThread中完全把消息发送完,但是ReadThread就没有保证能完全读完消息之后才允许退出,
比如这种情况,WriteThread正常执行,对端收到消息后会立刻回复相应消息, 回应的消息由ReadThread接收(其实ReadThread就是执行了一下recv函数),如果消息传输有延迟, ReadThread函数执行完的时候,消息还没有传输到服务端,这样的话recv岂不就没读到数据?
(1)这里的代码能避免上述情况吗?
(2)如果想实现一个安全,稳定的服务端收发消息的代码(MFC界面程序,消息量不大,最长的消息是4000字节左右),我读过的代码比较少, 不知道其他socket服务端进程是怎么实现的,能不能发个代码参考? 邮箱[email protected] ,谢谢了最后贴一下ReadThread的代码:UINT ReadThread(LPVOID param) {
    CComWnd *pComWnd=(CComWnd *)param;
    int ReadResults=0; 
    BOOL Ready=FALSE;
    BYTE* buffer=(BYTE*)malloc(sizeof(BYTE)*5036);    
    ReadResults=recv(socket,buffer,5036,0)
    int i=0;
    while(!Ready) {                            
        if(AddToReceiveBuffer(*(buffer+i))) {
            Ready=TRUE;    
        }
        i++;
    }
    free(buffer);
    return 0;
}

解决方案 »

  1.   


    LS能不能详细提示下? 3ks!
      

  2.   

    4000字节很小的,可以用UDP方式传输recvfrom sendto
      

  3.   

    服务端代码
    UINT __cdecl Listening( LPVOID pParam )
    {
    CMainFrame* pMainFram =  (CMainFrame*)pParam; pMainFram->hDataCopyEvent = CreateEvent(NULL, true, false, NULL);
    int err;
    CString csInfo;

    // Create a servernetwork object
    pMainFram->m_ServerNetwork.InitiateNetwork();

    do
    {
    // Listening for incoming data
    pMainFram->OutputDebugInfo(L"Listening...");
    err = pMainFram->m_ServerNetwork.RecvDatagram(pMainFram->m_cBuffer, 1024, pMainFram->m_SenderAddr);
    csInfo.Format(L"In coming data.Error code:0x%x", err);
    pMainFram->OutputDebugInfo(csInfo);
    csInfo.Format(L"Client ip:%d.%d.%d.%d  port:%d", 
    pMainFram-> m_SenderAddr.sin_addr.S_un.S_un_b.s_b1, 
    pMainFram-> m_SenderAddr.sin_addr.S_un.S_un_b.s_b2,
    pMainFram-> m_SenderAddr.sin_addr.S_un.S_un_b.s_b3,
    pMainFram-> m_SenderAddr.sin_addr.S_un.S_un_b.s_b4,
    ntohs(pMainFram-> m_SenderAddr.sin_port));
    pMainFram->OutputDebugInfo(csInfo); // Check hListenTheadEvent state for exit event
    if(WaitForSingleObject(pMainFram->hListenTheadEvent, 0) == WAIT_OBJECT_0)
    {
    // Signaled
    ResetEvent(pMainFram->hListenTheadEvent);
    pMainFram->OutputDebugInfo(L"Listening thread exit.");
    pMainFram->pListenThrad = NULL;
    return 1;
    } // Pass cmainfram to dataprocess thread
    AfxBeginThread(DataProcess, pParam);
    // Wait until copy complete
    WaitForSingleObject(pMainFram->hDataCopyEvent, INFINITE);
    ResetEvent(pMainFram->hDataCopyEvent);
    }
    while(err); pMainFram->pListenThrad = NULL;
    return 0;
    }#include "StdAfx.h"
    #include "ServerNetwork.h"
    #define GFXMONITORPORT 5013CServerNetwork::CServerNetwork(void)
    {
    }
    CServerNetwork::~CServerNetwork(void)
    {
    }int CServerNetwork::InitiateNetwork()
    {
    //Initiate use of the winscok all
    WORD wVersionRequested;
    WSADATA wsaData;
    int err; wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData);
    if(err != 0)
    {
    err = WSAGetLastError();
    WSACleanup();
    return err;
    } /*Confirm that the WinSock Dll supports 2.2*/ if(LOBYTE(wsaData.wVersion) != 2 ||
    HIBYTE(wsaData.wVersion) != 2)
    {
    err = WSAGetLastError();
    WSACleanup();
    return err;
    } /*The WinSock Dll is acceptable, proceed */ //Create a server socket
    m_wsaServerSocket = WSASocket(AF_INET,
    SOCK_DGRAM,
    IPPROTO_UDP,
    NULL,
    0,
    WSA_FLAG_OVERLAPPED); if(m_wsaServerSocket == INVALID_SOCKET)
    {
    err = WSAGetLastError();
    WSACleanup();
    return err;
    } //Craete a receive addr
    SOCKADDR_IN          ReceiverAddr;
    // Set up a SOCKADDR_IN structure that will tell bind that we
    // want to receive datagrams from all interfaces using port
    // 5150. ReceiverAddr.sin_family = AF_INET;
    ReceiverAddr.sin_port = htons(GFXMONITORPORT);  
    ReceiverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Associate the address information with the socket using bind. bind(m_wsaServerSocket, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr));
    return 0;
    }int CServerNetwork::RecvDatagram(CHAR* cBuffer, ULONG ulLength, sockaddr_in& SenderAddr)
    {
    DWORD BytesRecv = 0, Flags = 0;
    int SenderAddrSize = sizeof(SenderAddr), err = 0; //Create a wsabuf to hold the recv buffer
    WSABUF DataBuf;
    DataBuf.buf = cBuffer;
    DataBuf.len = ulLength; //Crate an event handle and setup a overlapped structure
    WSAOVERLAPPED RecvOverlapped; 
    RecvOverlapped.hEvent = WSACreateEvent(); err = WSARecvFrom(m_wsaServerSocket,
    &DataBuf,
    1,
    &BytesRecv,
    &Flags,
    (SOCKADDR *) &SenderAddr, 
    &SenderAddrSize,
    &RecvOverlapped,
    NULL); if(err == SOCKET_ERROR)
    {
    err = WSAGetLastError();
    if(err != WSA_IO_PENDING)
    {
    return err;
    }
    }
    if(RecvOverlapped.hEvent == NULL)
    {
    return WSAGetLastError();
    } err = WSAGetOverlappedResult(m_wsaServerSocket,
    &RecvOverlapped,
    &BytesRecv,
    TRUE,
    &Flags);
    if(err != TRUE)
    {
    return WSAGetLastError(); 
    } return err;
    }
    int CServerNetwork::SendDatagram(CHAR* cBuffer, ULONG ulLength, SOCKADDR_IN RecieverAddress)
    {
    DWORD BytesSend = 0, Flags = 0;
    int RecieverAddressSize = sizeof(RecieverAddress), err = 0; //Create a wsabuf to hold the recv buffer
    WSABUF DataBuf;
    DataBuf.buf = cBuffer;
    DataBuf.len = ulLength; //Crate an event handle and setup a overlapped structure
    WSAOVERLAPPED SendOverlapped; 
    SendOverlapped.hEvent = WSACreateEvent(); err = WSASendTo(m_wsaServerSocket,
    &DataBuf,
    1,
    &BytesSend,
    Flags,
    (SOCKADDR *)&RecieverAddress,
    RecieverAddressSize,
    &SendOverlapped,
    NULL); if(err == SOCKET_ERROR)
    {
    err = WSAGetLastError();
    if(err != WSA_IO_PENDING)
    {
    return err;
    }
    } err = WSAGetOverlappedResult(m_wsaServerSocket,
    &SendOverlapped,
    &BytesSend,
    TRUE,
    &Flags);
    if(err != TRUE)
    {
    return WSAGetLastError(); 
    } return err;
    }
    int CServerNetwork::CleanupNetwork()
    {
    // When the application is finished networking, close the socket.
    closesocket(m_wsaServerSocket); //---------------------------------------------
    // Clean up and quit.
    WSACleanup(); return 0;
    }
      

  4.   


    现在有些明白了,确实是用的阻塞sock,那么recv是一定可以执行完的
    这个帖子结了,还有写问题,另开个贴吧