Answer the question
In order to leave comments, you need to log in
Why does the client hang on recv?
Server code:
// ServerOne.cpp : Этот файл содержит функцию "main". Здесь начинается и заканчивается выполнение программы.
//
#include <iostream>
#include <WinSock.h>
#pragma comment (lib,"WS2_32.lib")
#include <fstream>
#include <algorithm>
#include <string>
#include <iterator>
void error(const char* msg)
{
//perror(msg);
std::cout<<'\n'<<WSAGetLastError();
WSACleanup();
std::cin.ignore();
exit(1);
}
void bzero(char*buf, int l)
{
for (int i = 0; i < l; i++)
buf[i] = '\0';
}
struct arg_s
{
char* buffer;
unsigned char* buffer2;
bool exit;
};
struct arg_sa
{
struct arg_s* lalk;
int current;
};
#define type struct arg_sa
int sockfd, * newsockfd;
int buflen2 = 4096;
struct sockaddr_in *cli_addr;
int* clilen;
int currentclient;
void session_(LPVOID args)
{
int current = currentclient++;
bzero((char*)&(cli_addr[current]), sizeof(&(cli_addr[current])));
newsockfd[current] = accept(sockfd, (struct sockaddr*)&(cli_addr[current]), &(clilen[current]));
if (newsockfd[current] < 0)
{
error("Error on accept\n");
}
// Определение контекстов
HDC ScreenDC = GetDC(0);
HDC MemoryDC = CreateCompatibleDC(ScreenDC);
// Фиксация размеров экрана
int ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
int ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
ScreenWidth = ((ScreenWidth - 1) / 4 + 1) * 4;
// Создание и частичное заполнение структуры формата
BITMAPINFO BMI;
BMI.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BMI.bmiHeader.biWidth = ScreenWidth;
BMI.bmiHeader.biHeight = ScreenHeight; // Отрицательное значение высоты, чтобы изображение не было перевёрнутым
BMI.bmiHeader.biSizeImage = ScreenWidth * ScreenHeight * 3; // Ширина * Высота * Количество_цветов_на_пиксель
BMI.bmiHeader.biCompression = BI_RGB;
BMI.bmiHeader.biBitCount = 24;
BMI.bmiHeader.biPlanes = 1;
DWORD ScreenshotSize;
ScreenshotSize = BMI.bmiHeader.biSizeImage; // ScreenshotSize - глобальная переменная типа int, может меняться в ходе выполнения программы
unsigned char* ImageBuffer; // Указатель на блок данных BGR, управляемый HBITMAP (да, именно BGR - не RGB)
HBITMAP hBitmap = CreateDIBSection(ScreenDC, &BMI, DIB_RGB_COLORS, (void**)&ImageBuffer, 0, 0);
SelectObject(MemoryDC, hBitmap);
BitBlt(MemoryDC, 0, 0, ScreenWidth, ScreenHeight, ScreenDC, 0, 0, SRCCOPY);
// Контексты больше не нужны
DeleteDC(MemoryDC);
ReleaseDC(NULL, ScreenDC);
FILE* sFile = 0; // Дескриптор файла
// Обьявляем переменные, которые понадобятся нам в дальнейшем:
unsigned char tgaHeader[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
unsigned char header[6];
unsigned char tempColors = 0;
// Открываем файл скриншота
fopen_s(&sFile,"Screen.tga", "wb");
// Проверяем, правильно ли произошло открытие
if (!sFile) {
}
// Записываем ширину и высоту:
header[0] = ScreenWidth % 256;
header[1] = ScreenWidth / 256;
header[2] = ScreenHeight % 256;
header[3] = ScreenHeight / 256;
header[4] = BMI.bmiHeader.biBitCount;
header[5] = 0;
// Записываем хидеры в начало файла:
fwrite(tgaHeader,1, sizeof(tgaHeader), sFile);
fwrite(header, sizeof(header), 1, sFile);
fwrite(ImageBuffer, BMI.bmiHeader.biSizeImage, 1, sFile);
// Закрываем файл
fclose(sFile);
FILE* f;
int n;
fopen_s(&f, "Screen.tga", "rb");
size_t bytes;
if (f != NULL)
{
while (1)
{
bytes = fread((char*)((type*)args)[current].lalk->buffer, sizeof(char), buflen2, f);
if (bytes <= 0)
break;
n = send(newsockfd[current], ((type*)args)[current].lalk->buffer, buflen2, 0);
}
fclose(f);
std::cout << "closing";
}
//Используем ImageBuffer как нам хочется... после удаляем его хендлер (HBITMAP) для избежания утечки памяти
DeleteObject(hBitmap);
}
int main()
{
WSADATA ws = { 0 };
if (WSAStartup(MAKEWORD(2, 2), &ws) == 0)
{
currentclient = 0;
int maxclients = 1;
cli_addr = new struct sockaddr_in[maxclients];
clilen = new int[maxclients];
for (int i = 0; i < maxclients; i++)
{
clilen[i] = sizeof(cli_addr[i]);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
struct sockaddr_in serv_addr;
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
int port = 30000;
serv_addr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
if (listen(sockfd, 10) < 0)
error("ERROR listen");
HANDLE* thread;
struct arg_sa* args;
while (true)
{
newsockfd = new int[maxclients];
thread = (HANDLE*)malloc(sizeof(HANDLE) * maxclients);
args = new struct arg_sa[maxclients];
for (int i = 0; i < maxclients; i++)
{
args[i].lalk = new struct arg_s();
args[i].lalk->buffer = new char[buflen2];
args[i].lalk->buffer2 = new unsigned char[buflen2];
}
int i = -1;
while (++i < maxclients)
{
Sleep(1);
args[i].current = i;
args[i].lalk->exit = false;
thread[i] = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)(session_), args, 0, 0);
}
for (int i = 0; i < maxclients; i++)
WaitForSingleObject(thread[i], INFINITE);
i = -1;
while (++i < maxclients)
{
shutdown(newsockfd[i], 0);
TerminateThread(thread[i], 0);
}
//delete[] newsockfd;
//free(thread);
currentclient = 0;
for (int i = 0; i < maxclients; i++)
{
//delete args[i].lalk;
//delete[] args[i].lalk->buffer;
}
//delete[] args;
}
shutdown(sockfd, 0);
WSACleanup();
return 0;
}
std::cin.ignore();
}
// ClientOne.cpp : Этот файл содержит функцию "main". Здесь начинается и заканчивается выполнение программы.
//
#include <iostream>
#include <WinSock.h>
#pragma comment (lib,"WS2_32.lib")
void error(const char* msg)
{
//perror(msg);
std::cout << '\n' << WSAGetLastError();
WSACleanup();
std::cin.ignore();
exit(1);
}
void bzero(char* buf, int l)
{
for (int i = 0; i < l; i++)
buf[i] = '\0';
}
int main()
{
WSADATA ws = { 0 };
if (WSAStartup(MAKEWORD(2, 2), &ws) == 0)
{
int sockfd;
struct hostent* server = gethostbyname("localhost");
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
struct sockaddr_in serv_addr, cli_addr;
bzero((char*)&serv_addr, sizeof(serv_addr));
bzero((char*)&cli_addr, sizeof(cli_addr));
serv_addr.sin_family = AF_INET;
const char* address = "127.0.0.1";
serv_addr.sin_addr.s_addr = inet_addr(address);
int port = 30000;
serv_addr.sin_port = htons(port);
int servlen = sizeof(serv_addr);
int n = connect(sockfd, (struct sockaddr*)&serv_addr, servlen);
if (n < 0)
{
error("ERROR on connect");
}
unsigned int buflen2 = 4096;
char* buffer = new char[buflen2];
FILE* f;
fopen_s(&f, "Screen.tga", "wb");
if (f != NULL)
{
while (1)
{
n = recv(sockfd, buffer, buflen2, 0);
if (n <= 0)
break;
fwrite(buffer, sizeof(char), buflen2, f);
}
fclose(f);
}
system("Screen.tga");
shutdown(sockfd, 0);
WSACleanup();
delete[] buffer;
return 0;
}
std::cin.ignore();
}
Answer the question
In order to leave comments, you need to log in
Why does the client hang on recv?
Because before closing the socket, you need to do shutdown(sock, SD_BOTH ), and not 0. And you need to destroy the socket with the function int closesocket( IN SOCKET s);. Otherwise, the client will wait forever for data or until the server process dies. But your server will die its death only because of memory leaks.
while (++i < maxclients)
{
shutdown(newsockfd[i], SD_BOTH);
closesocket(newsockfd[i]);
// TerminateThread(thread[i], 0);
CloseHandle(thread[i]);
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question