Почему \ n остановить следующий сокет отправки?С - PullRequest
0 голосов
/ 08 октября 2018

Я пытался поставить \0 в конце сообщения, но это не сработало.Я также поместил завершающий символ при получении сокета на стороне клиента, но это тоже не сработало.Вот изображение консоли:

console output

на стороне сервера:

char u[BUFFER]

char *msg = "You are required to enter username:\n\n";
send(clie, msg, strlen(msg), 0);
// not shown on console
char *u_msg = "Username: ";
send(clie, u_msg, strlen(u_msg), 0);
recv(clie, u, sizeof(u), 0);

на стороне клиента

char srecv[BUFFER]; // BUFFER = 1024
while (1) {
    bytes = recv(ser, & srecv, BUFFER, 0);
    srecv[bytes] = '\0';
    printf("%s", srecv);
    scanf("%s", ssend);
    if (send(ser, ssend, strlen(ssend), 0) == -1) {
        perror("send\n");
        exit(1);
    }  
}

1 Ответ

0 голосов
/ 08 октября 2018

Поскольку в сообщениях вашего сервера несколько символов '\n', этого недостаточно, чтобы сообщить клиенту о завершении получения каждого сообщения.Вы должны либо:

  1. отправить длину сообщения перед отправкой фактического сообщения.

  2. отправить уникальный терминатор в конце каждого сообщения (вв вашем примере будет достаточно нулевого терминатора).

В любом случае клиент будет продолжать читать и отображать байты сообщения на консоли до тех пор, пока не будет достигнут истинный конец сообщения, ДОзатем чтение ответа пользователя из консоли.Клиент ДОЛЖЕН дождаться получения обоих сообщений целиком, прежде чем затем вызвать scanf().

. В TCP нет отношения 1: 1 между send() и recv(), вы ДОЛЖНЫ быть готовы обработать это.Обе функции МОГУТ вернуть меньше байтов, чем запрошено, поэтому обе функции должны вызываться в циклах, пока все ожидаемые байты не будут отправлены / получены.И сообщения ДОЛЖНЫ быть явно оформлены отправителем таким образом, чтобы получатель знал, когда сообщение действительно заканчивается.

Вместо этого попробуйте что-то более похожее на это:

Общий код для обеих сторон:

int sendAll(int sckt, const void *data, size_t size)
{
    const char *pdata = (const char*) data;
    while (size > 0)
    {
        ssize_t sent = send(sckt, pdata, size, 0);
        if (sent < 0) return -1;
        pdata += sent;
        size -= sent;
    }
    return 0;
}

int recvAll(int sckt, void *data, size_t size)
{
    char *pdata = (char*) data;
    while (size > 0)
    {
        ssize_t recvd = recv(sckt, pdata, size, 0);
        if (recvd <= 0) return recvd;
        pdata += recvd;
        size -= recvd;
    }
    return 1;
}

int sendMsg(int sckt, const char *msg)
{
    uint32_t msglen = strlen(msg);
    uint32_t temp = htonl(msglen);
    int ret = sendAll(sckt, &temp, sizeof(temp));
    if (ret == 0) ret = sendAll(sckt, msg, msglen);
    return ret;
}

int recvMsg(int sckt, char **msg)
{
    *msg = NULL;

    uint32_t msglen = 0;
    int ret = recvAll(sckt, &msglen, sizeof(msglen));
    if (ret <= 0) return ret;
    msglen = ntohl(msglen);

    char *pmsg = (char*) malloc(msglen+1);
    if (!pmsg) return NULL;
    if (msglen > 0)
    {
        ret = recvAll(sckt, pmsg, msglen);
        if (ret <= 0)
        {
            free(pmsg);
            return ret;
        }
    }
    pmsg[msglen] = '\0';

    *msg = pmsg;
    return 1;
}

В качестве альтернативы:

int sendMsg(int sckt, const char *msg)
{
    if (!msg) msg = "\0";

    int size = strlen(msg) + 1;
    do
    {
        ssize_t sent = send(sckt, msg, size, 0);
        if (sent < 0) return -1;
        msg += sent;
        size -= sent;
    }
    while (size > 0);

    return 0;
}

int recvMsg(int sckt, char **msg)
{
    char c, buf[1024];
    int inbuf = 0;

    char *pmsg = NULL;
    int msglen = 0;

    *msg = NULL;

    do
    {
        ssize_t ret = recv(sckt, &c, 1, 0);
        if (ret <= 0)
        {
            if (pmsg) free(pmsg);
            return ret;
        }

        if (c == '\0')
            break;

        if (inbuf == sizeof(buf))
        {
            char *newmsg = (char*) realloc(msg, msglen + inbuf + 1);
            if (!newmsg)
            {
                if (pmsg) free(pmsg);
                return -1;
            }

            memcpy(buf, &newmsg[msglen], inbuf);
            newmsg[msglen + inbuf] = '\0';

            pmsg = newmsg;
            msglen += inbuf;

            inbuf = 0;
        }

        buf[inbuf] = c;
        ++inbuf;
    }
    while (1);

    if ((inbuf > 0) || (msglen == 0))
    {
        char *newmsg = (char*) realloc(msg, msglen + inbuf + 1);
        if (!newmsg)
        {
            if (pmsg) free(pmsg);
            return -1;
        }

        if (inbuf > 0) memcpy(buf, &newmsg[msglen], inbuf);
        newmsg[msglen + inbuf] = '\0';

        pmsg = newmsg;
    }

    *msg = pmsg;
    return 1;
}

Сторона сервера:

sendMsg(clie, "You are required to enter username:\n\n");
sendMsg(clie, "Username: ");

char *u;
if (recvMsg(clie, &u) == 1)
{
    ...
    free(u);
}

Сторона клиента:

char *msg;
while (1) {
    ret = recvMsg(ser, &msg);
    if (ret <= 0)
    {
        if (ret < 0)
        {
            perror("recvMsg\n");
            exit(1);
        }
        break;
    }

    printf("%s", msg);

    if (strcmp(msg, "Username: ") == 0)
    {
        scanf("%s", ssend);
        if (sendMsg(ser, ssend) == -1)
        {
            perror("sendMsg\n");
            exit(1);
        } 
    }

    free(msg);
}
...