GeorgeZv Ответов: 0

Мультиплексирование передачи сообщений ввода-вывода (чат клиент-сервер)


Всем привет,

Я новичок в C (как и в программировании) и изучаю сокеты Windows.
Я хочу написать простой чат между сервером и 2 клиентами (идеально сервер должен отправлять сообщения для всех, клиент только для сервера), и я столкнулся с проблемой.

Что я уже пробовал:

Из части** server * * я не могу получать сообщения от клиента до того, как отправлю сообщение клиенту. Тогда я теряю возможность отправлять сообщения из-за курсивов.

От * * клиента * * часть: клиент не получает сообщение сервера. В чем причина? Я проверил, доступны ли дескрипторы файлов чтения и записи (status = 1).

Кроме того, если я пытаюсь отправить сообщения от клиента, а затем отправить сообщение с сервера, я могу ввести clien console только один раз, а затем получить ошибку 10053 (установленное соединение было прервано программным обеспечением на вашем хост-компьютере, возможно, из-за тайм-аута передачи данных или ошибки протокола), но не могу найти ошибку в серверной части. После этого в серверной части, где я проверяю запись и чтение FD, я начинаю получать свои отладочные сообщения, эти дескрипторы получили статус = 0, и я не понимаю, почему (вероятно, потому что в сокете нет активности? Поскольку это мультиплексирование ввода-вывода, но меня больше интересует моя проблема с сообщением).

Это** сервер * * вывод:
Setup SERVER socket descriptor number: 272
We have 1 user online
New client 127.0.0.1:64590
Read FD: 1
Write FD: 1
Server -> Client: Check after 1 and 2
Read FD: 1
Write FD: 1
Client -> Server: Check 1
Check 2

Read FD: 0
Write FD: 0


Это** клиент * * вывод:
Attempt to connect 127.0.0.1:3765
Local address: 127.0.0.1:3765 of server:
Connection with 127.0.0.1
Client -> Server: Check 1
Client -> Server: Check 2
Client -> Server: trying to write smth
Client -> Server: aaand fail
Send error - Error code: 10053


Это код сервера:

#pragma comment(lib, "ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
//#include "list.h"

#define PRINTUSERS if (nclients)\
    printf("We have %d user online\n", nclients);\
    else printf("No users online\n***************\n");

#define PORT 3765
#define BACKLOG 10
#define MAXDATASIZE 1024
#define MAXUSERSONLINE 64

int main(int argc, char* argv[])
{
    struct sockaddr_in serverAddr;
    struct sockaddr_in clientAddr;

    SOCKET socketDescriptor;
    fd_set readSocketDescriptor;
    fd_set writeSocketDescriptor;
    int newSocketDescriptor;

    WSADATA wsaData;
    WORD wsaStart;
    timeval tv;

    int retVal;
    int clientAddrSize = sizeof(clientAddr);
    char bufferData[MAXDATASIZE] = { 0 };
    int nclients = 0;
    int numBytes = 0;

    if (argc > 1)
    {
        printf("Uses: <chatserver>\n");
        return -1;
    }
    do
    {
        if ((wsaStart = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
        {
            printf("WSAStartup error ");
            break;
        }
        if ((socketDescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
        {
            printf("Socket error ");
            closesocket(socketDescriptor);
            break;
        }

        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(PORT);
        serverAddr.sin_addr.s_addr = INADDR_ANY;

        if (bind(socketDescriptor, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
        {
            printf("Bind error ");
            closesocket(socketDescriptor);

            break;
        }
        if (listen(socketDescriptor, BACKLOG) == SOCKET_ERROR)
        {
            printf("Listening error ");
            closesocket(socketDescriptor);
            break;
        }

        printf("Setup SERVER socket descriptor number: %d\n", socketDescriptor);
        tv.tv_sec = 5;

        while (1)
        {
            // Do not forget to put after WHILE(1)
            FD_ZERO(&readSocketDescriptor);
            FD_ZERO(&writeSocketDescriptor);
            FD_SET(socketDescriptor, &readSocketDescriptor);
            FD_SET(socketDescriptor, &writeSocketDescriptor);

            if ((retVal = select(socketDescriptor + 1, &readSocketDescriptor, &writeSocketDescriptor, NULL, &tv)) == SOCKET_ERROR)
            {
                printf("Select error ");
                break;
            }

            if ((FD_ISSET(socketDescriptor, &readSocketDescriptor)) != 0)
            {
                if ((newSocketDescriptor = accept(socketDescriptor, (struct sockaddr *)&clientAddr, &clientAddrSize)) == SOCKET_ERROR)
                {
                    printf("Accept error ");
                    break;
                }

                createSocketInformation(newSocketDescriptor);
                getSocketInformation(newSocketDescriptor);

                nclients++; PRINTUSERS
                printf("New client %s:%d \n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
                //FD_CLR(socketDescriptor, &readSocketDescriptor);
                FD_SET(newSocketDescriptor, &readSocketDescriptor);
                FD_SET(newSocketDescriptor, &writeSocketDescriptor);

                printf("Read FD: %d\n", FD_ISSET(newSocketDescriptor, &readSocketDescriptor));
                printf("Write FD: %d\n", FD_ISSET(newSocketDescriptor, &writeSocketDescriptor));
                printf("Server -> Client: ");
                fgets(&bufferData[0], sizeof(bufferData), stdin);

                if (FD_ISSET(newSocketDescriptor, &writeSocketDescriptor) != 0)
                {

                    if (send(newSocketDescriptor, &bufferData[0], MAXDATASIZE, 0) == SOCKET_ERROR)
                    {
                        printf("Send error ");
                        freeSocketInformation(newSocketDescriptor);
                        break;
                    }
                //FD_CLR(newSocketDescriptor, &writeSocketDescriptor);
                //FD_SET(newSocketDescriptor, &writeSocketDescriptor);
                }
            }
            printf("Read FD: %d\n", FD_ISSET(newSocketDescriptor, &readSocketDescriptor));
            printf("Write FD: %d\n", FD_ISSET(newSocketDescriptor, &writeSocketDescriptor));
            if (FD_ISSET(newSocketDescriptor, &readSocketDescriptor) != 0)
            {
                if ((numBytes = recv(newSocketDescriptor, &bufferData[0], MAXDATASIZE, 0)) == SOCKET_ERROR)
                {
                    printf("Recv failed \n");
                    freeSocketInformation(newSocketDescriptor);
                    break;
                }

                bufferData[numBytes] = '\0';
                printf("Client -> Server: %s\n", &bufferData[0]);
                if (numBytes == -1)
                {
                    printf("One user has disconnected");
                    nclients--;
                    PRINTUSERS
                }
                else
                {
                    char *testmsg = "Hello, new user, you're welcome\n";
                    if (send(newSocketDescriptor, testmsg, strlen(testmsg), 0) == SOCKET_ERROR)
                    {
                        printf("Send error ");
                        freeSocketInformation(newSocketDescriptor);
                        break;
                    }
                    FD_CLR(newSocketDescriptor, &readSocketDescriptor);
                }
                FD_SET(newSocketDescriptor, &readSocketDescriptor);
            }
            /*else
            {
                printf("Sorry, time limit is expired, there is no active sockets\n");
                freeSocketInformation(newSocketDescriptor);
            }*/
            closesocket(newSocketDescriptor);
        }
        closesocket(socketDescriptor);
    } while (FALSE);
    printf("- Error code: %d\n", WSAGetLastError());
    WSACleanup();
    return 0;
}

И клиентская часть:
#pragma comment(lib, "ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>

#define SERVERADDR argv[1]
#define PORT 3765
#define MAXDATASIZE 1024

int main(int argc, char *argv[])
{
    struct sockaddr_in serverAddr = { 0 };
    struct sockaddr_in clientAddr = { 0 };
    SOCKET socketDescriptor;
    WSADATA wsaData;
    fd_set readSet;
    fd_set writeSet;
    timeval tv;

    char bufferData[MAXDATASIZE];
    int numBytes;
    unsigned long int nb = 1;
    int retVal;

    if (argc != 2)
    {
        printf("Uses: <client> <hostname>\nExample: \"client 127.0.0.1\"\n");
        return -1;
    }
    do
    {
        if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        {
            printf("WSAStartup error ");
            break;
        }
        if (gethostbyname(SERVERADDR) == NULL)
        {
            printf("Gethostbyname error ");
            break;
        }
        if ((socketDescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
        {
            printf("Socket error ");
            break;
        }
        if (ioctlsocket(socketDescriptor, FIONBIO, (unsigned long *)&nb) != 0)
        {
            printf("ioctlsocket error ");
            break;
        }

        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(PORT);
        serverAddr.sin_addr.s_addr = inet_addr(SERVERADDR);

        printf("Attempt to connect %s:%d\n", inet_ntoa(serverAddr.sin_addr), htons(serverAddr.sin_port));
        tv.tv_sec = 20;

        if (connect(socketDescriptor, (sockaddr *)&serverAddr, sizeof(serverAddr)))
        {
            getsockname(socketDescriptor, (struct sockaddr *)&clientAddr, (int*)sizeof(clientAddr));
            printf("Local address: %s:%d of server:\n", inet_ntoa(serverAddr.sin_addr), ntohs(serverAddr.sin_port));
            FD_ZERO(&writeSet);
            FD_SET(socketDescriptor, &writeSet);
            if ((retVal = select(socketDescriptor + 1, NULL, &writeSet, NULL, &tv)) == SOCKET_ERROR)
            {
                printf("Send non-blocking error ");
                break;
            }
            else if (retVal == 0)
            {
                printf("Non-blocking connect time limit is expired");
                break;
            }
        }
        printf("Connection with %s\n", SERVERADDR);

        while (1)
        {
            FD_ZERO(&readSet);
            FD_ZERO(&writeSet);
            FD_SET(socketDescriptor, &readSet);
            FD_SET(socketDescriptor, &writeSet);

            if ((retVal = select(socketDescriptor + 1, &readSet, &writeSet, NULL, &tv)) == SOCKET_ERROR)
            {
                printf("Select error ");
                break;
            }
            else if (retVal == 0)
            {
                printf("Time limit is expired ");
                continue;
            }
            char *testmsg = "Hello, I'm a new user online\n";
            printf("Client -> Server: ");
            fgets(&bufferData[0], sizeof(bufferData), stdin);
            if (FD_ISSET(socketDescriptor, &writeSet) != 0)
            {
                //send(socketDescriptor, testmsg, strlen(testmsg), 0);
                if (send(socketDescriptor, &bufferData[0], strlen(&bufferData[0]), 0) == SOCKET_ERROR)
                {
                    printf("Send error ");
                    break;
                }
            }

            if (FD_ISSET(socketDescriptor, &readSet) != 0)
            {
                if ((numBytes = recv(socketDescriptor, &bufferData[0], MAXDATASIZE, 0)) == SOCKET_ERROR)
                {
                    printf("Recv error ");
                    break;
                }
                bufferData[numBytes] = '\0';
                printf("Server -> Client: %s\n", &bufferData[0]);
            }
        }
    } while (FALSE);
    printf("- Error code: %d\n", WSAGetLastError());
    closesocket(socketDescriptor);
    WSACleanup();
    return 0;
}

Спасибо за любую помощь

0 Ответов