我通过winsock2创建了一个服务器/客户端。客户端获取bmp屏幕截图,将其压缩为jpeg并将其发送到服务器。我遇到的问题是服务器在将文件保存到磁盘时遇到问题。就像数据没有接收权一样。我认为这与我发送或接收缓冲区的方式有关。
编辑:在调试期间从设置breakpoints
看起来好像收到了所有数据。 istream->Write
返回与Size
相关的正确字节数,istream->Seek
返回S_OK
,CLSID
COM对象包含与发送的数据相同的数据。在我发送缓冲区之前,我测试它以查看它是否保存并且确实如此。因此,我假设它必须是发送或接收缓冲区的方式。
编辑: 在两端,缓冲区看起来像This
屏幕截图加发送代码。
ScreenShot(Packet_Handler* _Handle)
{
IStream* istream;
//char* Buff;
HRESULT res = CreateStreamOnHGlobal(NULL, true, &istream);
Gdiplus::GdiplusStartupInput gdiInput;
ULONG_PTR gdiToken;
Gdiplus::GdiplusStartup(&gdiToken, &gdiInput, NULL);
{
HDC scrdc, memdc;
HBITMAP membit;
scrdc = ::GetDC(0);
int Height = GetSystemMetrics(SM_CYSCREEN);
int Width = GetSystemMetrics(SM_CXSCREEN);
memdc = CreateCompatibleDC(scrdc);
membit = CreateCompatibleBitmap(scrdc, Width, Height);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, scrdc, 0, 0, SRCCOPY);
Gdiplus::Bitmap bitmap(membit, NULL);
CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
bitmap.Save(istream, &clsid, NULL);
bitmap.Save(L"Test.jpeg", &clsid, NULL); //THIS WORKS
STATSTG pstatstg = { 0 };
istream->Stat(&pstatstg, 0);
ULONG Bytes;
char* isBuff = new char[pstatstg.cbSize.QuadPart];
LARGE_INTEGER li;
li.QuadPart = 0;
istream->Seek(li, STREAM_SEEK_SET, NULL);
if (istream->Read(isBuff, pstatstg.cbSize.QuadPart, &Bytes) == S_OK)
{
IStream* nistream = nullptr;
ULONG nBytes;
CreateStreamOnHGlobal(NULL, true, &nistream);
if (nistream->Write(isBuff, pstatstg.cbSize.QuadPart, &Bytes) == S_OK)
{
if (nistream->Seek(li, STREAM_SEEK_SET, NULL) == S_OK)
{
Gdiplus::Bitmap bitmap2(nistream, NULL);
bitmap2.Save(L"Testing.jpeg", &clsid, NULL); //THIS WORKS
}
}
}
int Size = pstatstg.cbSize.QuadPart;
int SOLI = sizeof(ULARGE_INTEGER);
int SOCID = sizeof(CLSID);
int SOIS = sizeof(IStream);
Send_Full_Packet(_Handle, &Size, isBuff, TRUE);
Send_Full_Packet(_Handle, &SOCID, &clsid, FALSE);
printf("saving Screenshot");
DeleteObject(memdc);
DeleteObject(membit);
::ReleaseDC(0, scrdc);
}
Gdiplus::GdiplusShutdown(gdiToken);
_getch();
return 0;
}
void Send_Full_Packet(Packet_Handler* _Handle, int* pSize, void * Buff, bool ispchar)
{
int SentPackets = 0;
int sCheck = 0;
int rCheck = 0;
int Size = *pSize;
char* isBuff;// = new char[Size];
sCheck = send(_Handle->ConnectSocket, (char*)&Size, sizeof(int), NULL);
int PacketsSent = 0;
sCheck = 0;
int PacketsLeft = Size;
while (PacketsSent < Size)
{
if (ispchar == FALSE)
{
SentPackets = send(_Handle->ConnectSocket, (char*)Buff + PacketsSent, PacketsLeft, NULL);
}
else {
isBuff = (char*)Buff;
SentPackets = send(_Handle->ConnectSocket, isBuff + PacketsSent, PacketsLeft, NULL);
}
if (SentPackets == SOCKET_ERROR)
{
if (WSAGetLastError() != 10054)
{
if (WSAGetLastError() == 10035)
{
SentPackets == 0;
}
else
{
printf("Sending Socket error: %d\n", WSAGetLastError());
break;
}
}
}
PacketsSent += SentPackets;
PacketsLeft -= SentPackets;
}
}
接收代码
ScreenShot_Receive_Thread(Packet_Handler* _Handle)
{
Packet_Handler::_Packet_Type Packet = Packet_Handler::_Packet_Type::Remote;
while (true)
{
if (send(_Handle->si.Connections[_Handle->si.ConnectionCounter - 1], (char*)&Packet, sizeof(Packet_Handler::_Packet_Type), 0) != INVALID_SOCKET)
{
while (true)
{
int Size = 0;
char* Buff = NULL;
Buff = _Handle->Receive_Full_Packet(_Handle, &Size, Buff, TRUE);
CLSID clsid;
int SOCID = sizeof(CLSID);
_Handle->Receive_Full_Packet(_Handle, &SOCID, &clsid, FALSE);
IStream* istream = nullptr;
ULONG Bytes;
CreateStreamOnHGlobal(NULL, true, &istream);
if (istream->Write(Buff, Size, &Bytes) == S_OK)
{
LARGE_INTEGER li;
li.QuadPart = 0;
if (istream->Seek(li, STREAM_SEEK_SET, NULL) == S_OK)
{
Gdiplus::Bitmap bitmap(istream, NULL);
bitmap.Save(L"Testing.jpeg", &clsid, NULL);//DOESNT WORK
}
}
}
}
}
MessageBox(NULL, L"CLient COnnection Error!", NULL, NULL);
return 0;
}
char* Packet_Handler::Receive_Full_Packet(Packet_Handler * _Handle, int* pSize, void * Buff, bool ispchar)
{
int rCheck = 0;
int sCheck = 0;
int Size = *pSize;
rCheck = recv(_Handle->si.Connections[_Handle->si.ConnectionCounter - 1], (char*)&Size, sizeof(int), 0);
if (rCheck == -1)
{
int Error = WSAGetLastError();
AllocConsole();
freopen("CONOUT$", "w", stdout);
std::cout << "The Error is: " << Error << std::endl;
}
*pSize = Size;
char* isBuff;// = NULL;
int PacketsReceived = 0;
int PacketsLeft = Size;
int ReceivedPackets = 0;
while (PacketsReceived < Size)
{
if (ispchar == FALSE)
{
ReceivedPackets = recv(_Handle->si.Connections[_Handle->si.ConnectionCounter - 1], (char*)Buff + PacketsReceived, PacketsLeft, 0);
}
else
{
isBuff = new char[Size]; //I Think my problem is here//
ReceivedPackets = recv(_Handle->si.Connections[_Handle->si.ConnectionCounter - 1], isBuff + PacketsReceived, PacketsLeft, 0);
}
if (ReceivedPackets == SOCKET_ERROR)
{
int Error = WSAGetLastError();
if (Error != 10054)
{
if (Error == 10035 || Error == 6)
{
ReceivedPackets == 0;
}
else
{
AllocConsole();
freopen("CONOUT$", "w", stdout);
std::cout << "The Error is: " << Error << std::endl;
//MessageBox(NULL, (WCHAR*)WSAGetLastError(), NULL, NULL);
_getch();
//return NULL;
break;
}
}
}
PacketsReceived += ReceivedPackets;
PacketsLeft -= ReceivedPackets;
}
return isBuff;
}
答案 0 :(得分:0)
数据可能需要多次recv
来电才能完全接收。发生这种情况时,Receive_Full_Packet
为每个此类呼叫分配一个新缓冲区,并迅速泄漏其中一个。它返回给调用者的是最后一次这样的分配 - 一个大部分是未初始化的缓冲区,里面装满了随机垃圾,最后一块数据就在它的最后。
将isBuff = new char[Size];
行移到循环之外,在检索到大小的第一个recv
调用之后将其放置。
答案 1 :(得分:0)
终于搞清楚了。事实证明,我发送缓冲区的方式绝对没有错。它实际上是CLSID
。我最终将GetEncoderClsid
函数放在接收端。像黄油一样工作。