找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4349|回复: 5

请问该如何正确接收大数据量的数据

[复制链接]
发表于 2008-9-21 15:18:11 | 显示全部楼层 |阅读模式
公司现正做一个项目,做一个服务器
该服务器实现同其他公司的通信接口,对其他的公司的通信接口来说
我的服务器是客户端
同时我的服务器还要管理自己写的一些客户端
框架是这样的
别的接口发送数据给我的服务器
但是该数据有可能比较大,比如可能有10000个字符,(我们接收的数据全是ascii)
我在实现接收的时候,该怎么做,只使用recv()就可以了么?
这样好像有很多数据接收不到?
有人说发送的时候将那10000个字符分开来发,但是与我们相连的接口协议中并没有标示
其在发送数据的时候将大数据拆分来发
请问我该怎么做?
谢谢
 楼主| 发表于 2008-9-21 15:18:17 | 显示全部楼层
因为没有细节信息,我只能猜测你们的实际情况,以此来发表看法。
1、你的软件既是服务器又是客户端?还是一个服务器程序,需要服务自己的客户端和外面公司的机器,你没写清楚。
2、用TCP传输数据,最好自定义一下头部信息,比如一次传输数据的长度、结束信息等等,解析起来容易。如果没法定义,只能循环收取了。不管发送的数据有多少字节,你只管每次收取一点,如4K,循环收取并且存储、处理即可。
3、没有数据收不到的情况,TCP已经保证了可靠性。
 楼主| 发表于 2008-9-21 15:18:27 | 显示全部楼层
是这样的,其实,我自己的服务器也紧紧是一个转发的机能

并没有其他的功能

是使用完成端口做的

问题是,现在的其他公司做的接口在发送数据的时候,其TCP的数据没有明确的定义数据头相关信息

而且,在使用完成端口中,我不知道该怎么样进行循环接收数据

我按照标准的完成端口机制,在工作线程中使用GetQueuedCompletionStatus,得到缓冲区的字节数

然后读取,并根据重叠数据的结构,进行相关处理,发送下一个wsarecv

工作线程的代码如下


DWORD WINAPI WorkThread(LPVOID lpParam)
{
   DWORD BytesTransferred;
   CClientContext* pPerHandleData = NULL;
   LPPER_IO_OPERATION_DATA pPerIoData = NULL;
   int nResult;
   
   while(TRUE)
   {  
    if (GetQueuedCompletionStatus(g_hIOCompletionPort, &BytesTransferred,
     (LPDWORD)&pPerHandleData, (LPOVERLAPPED *) &pPerIoData, INFINITE) == 0)
    {
     char strErr[256];
     wsprintf(strErr, "GetQueuedCompletionStatus failed with error %d",GetLastError());
     WriteDebugInfo(strErr);
     RemoveFromClientListAndFreeMemory(pPerHandleData);
     GlobalFree(pPerIoData);
     return 0;
    }
   
    // First check to see if an error has occured on the socket and if so
      // then close the socket and cleanup the SOCKET_INFORMATION structure
      // associated with the socket.
      if (BytesTransferred == 0)
      {
    if (closesocket(pPerHandleData->GetSocket()) == SOCKET_ERROR)
    {
     char strErr[256];
     wsprintf(strErr, "closesocket() failed with error %d",WSAGetLastError());
     WriteDebugInfo(strErr);
     RemoveFromClientListAndFreeMemory(pPerHandleData);   
     GlobalFree(pPerIoData);  
     return 0;
    }

    RemoveFromClientListAndFreeMemory(pPerHandleData);   
    GlobalFree(pPerIoData);  
    continue;
      }
   
   switch(pPerIoData->oper)
   {
   case SVR_IO_WRITE:
    ZeroMemory(pPerIoData,sizeof(PER_IO_OPERATION_DATA));
   
    pPerIoData->Overlapped.hEvent = NULL;
    pPerIoData->Overlapped.Internal = 0;
    pPerIoData->Overlapped.InternalHigh = 0;
    pPerIoData->Overlapped.Offset = 0;
    pPerIoData->Overlapped.OffsetHigh = 0;
   
    pPerIoData->DataBuf.buf = (char*)&(pPerIoData->Buffer);
    pPerIoData->DataBuf.len = DATA_BUFSIZE;
    pPerIoData->oper = SVR_IO_READ;
    pPerIoData->flags = 0;
   
    char strTmpB[DATA_BUFSIZE];
    wsprintf(strTmpB,"before recv+++++++++++++%s",pPerIoData->Buffer);
    WriteDebugInfo(strTmpB,1);
   
    nResult = WSARecv(pPerHandleData->GetSocket(), &(pPerIoData->DataBuf),1,NULL,&(pPerIoData->flags),&(pPerIoData->Overlapped),NULL);
   
    char strTmp[DATA_BUFSIZE];
    wsprintf(strTmp,"after recv______________%s",pPerIoData->Buffer);
    WriteDebugInfo(strTmp,1);
   
    if((nResult == SOCKET_ERROR) && (WSAGetLastError() != ERROR_IO_PENDING))
    {
     WriteDebugInfo("WSARecv Error\n");
     
     RemoveFromClientListAndFreeMemory(pPerHandleData);
     GlobalFree(pPerIoData);
    }
    break;
   case SVR_IO_READ:
    {  
     pPerIoData->DataBuf.len = BytesTransferred;
     pPerIoData->oper = SVR_IO_WRITE;
     pPerIoData->flags = 0;
     
     if((nResult == SOCKET_ERROR) &&
      (WSAGetLastError() != ERROR_IO_PENDING))
     {
      WriteDebugInfo("WSASend ERROR\n");
      RemoveFromClientListAndFreeMemory(pPerHandleData);
      GlobalFree(pPerIoData);
     }  
     
     char strTmp[DATA_BUFSIZE];
     wsprintf(strTmp,"___________________________%s\n\n\n",pPerIoData->DataBuf.buf);
     // WriteDebugInfo(pPerIoData->DataBuf.buf);
     
     WriteDebugInfo(strTmp);
     
     //................
    // char ss[] = "123456789";
    // send(pPerHandleData->GetSocket(),ss,sizeof(ss),0);
     
     SendNextRequest( pPerIoData,  pPerHandleData);
    }
    break;
   default:
    break;
   }   
   }
   return 1;
}


void SendNextRequest(LPPER_IO_OPERATION_DATA lpPerIOData, CClientContext* pClientContext)
{
ZeroMemory(lpPerIOData,sizeof(PER_IO_OPERATION_DATA));

lpPerIOData->Overlapped.hEvent = NULL;
lpPerIOData->Overlapped.Internal = 0;
lpPerIOData->Overlapped.InternalHigh = 0;
lpPerIOData->Overlapped.Offset = 0;
lpPerIOData->Overlapped.OffsetHigh = 0;

lpPerIOData->DataBuf.buf = (char*)&(lpPerIOData->Buffer);
lpPerIOData->DataBuf.len = DATA_BUFSIZE;
lpPerIOData->oper = SVR_IO_READ;
lpPerIOData->flags = 0;

int nResult = WSARecv(pClientContext->GetSocket(),&(lpPerIOData->DataBuf),1,NULL,
  &(lpPerIOData->flags),&(lpPerIOData->Overlapped),NULL);


if((nResult == SOCKET_ERROR) && (WSAGetLastError() != ERROR_IO_PENDING))
{
  WriteDebugInfo("WSARecv Error in SendNextRequest",1);
  RemoveFromClientListAndFreeMemory(pClientContext);
  GlobalFree(lpPerIOData);
}
// WriteDebugInfo("&&&&&&&&&&&&&&&&&&&&&&&&&");
// char strTmp[DATA_BUFSIZE];
// wsprintf(strTmp,"!!!!!!!!!!!!!!!!!!!!!!!!%s",lpPerIOData->DataBuf.buf);
// WriteDebugInfo(strTmp,1);
}


劳驾了,棒忙看看吧
 楼主| 发表于 2008-9-21 15:18:33 | 显示全部楼层
思路我觉得没错啊。

所谓循环收取并转发,就是WSARecv后,处理数据,并且再次投递一次异步的WSARecv操作,仅此而已。
至于没有结束标志,那也没关系了,只管收取,在不出错误的情况下,收取一次,投递一次异步操作,直到完成为止。
 楼主| 发表于 2008-9-21 15:18:39 | 显示全部楼层
先谢了

问题是,我需要获得别人发送的完整的大数据

比如别人发送的是10000个字符

我需要将这10000个字符完整的得到

然后再进行下一步操作该数据

这我该怎么实现呢?

而且,当网络繁忙的时候,完成端口中的多线程都在等待WSARecv,会不会出现这样的情况

线程1正循环接收一个10000的字符串A,在接收了8000个的时候,另一个字符串B发送过来

这时还是线程1来处理字符串B,那么最后我该怎么样整理这些字符串A和字符串B

谢谢
 楼主| 发表于 2008-9-21 15:18:45 | 显示全部楼层
如果没有长度标志,你无法知道对方给你发送了多少字节,只有结束通讯后才能统计出来。所以,第一个问题无解。你能做的,就是在socket没有断开的时候,一直收取并转发数据。
第二个问题,你可以在重叠数据结构里面,加上收取的序列号码和对应的句柄数据,就能做数据的区分和对应了。
本站有个完成端口模型的框架代码,里面展示的技巧很清晰。
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-5-19 14:30 , Processed in 0.326684 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表