Gremlin92
@Gremlin92
Ленивый и безъинициативный

Почему клиент висит на recv?

Код сервера:
// 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();
}
  • Вопрос задан
  • 55 просмотров
Пригласить эксперта
Ответы на вопрос 2
jcmvbkbc
@jcmvbkbc
http://dilbert.com/strip/1998-08-24
Почему клиент висит на recv?

Потому что с той стороны никто не прислал данных.
Код не читал.
Ответ написан
@none7
Потому, что перед закрытием сокета нужно делать shutdown(sock, SD_BOTH), а не 0. И нужно уничтожить сокет функцией int closesocket( IN SOCKET s);. Иначе клиент будет ждать данных вечно или пока процесс сервера не умрёт. Но Ваш сервер своей смертью умрёт только из за утечек памяти.
while (++i < maxclients)
 {
     shutdown(newsockfd[i], SD_BOTH);
     closesocket(newsockfd[i]);
//     TerminateThread(thread[i], 0);
    CloseHandle(thread[i]);
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы