Отправка буфера в c сокет программирования с записью - PullRequest
0 голосов
/ 18 марта 2019

Я создаю TCP-чат в C с fork(). Каждое клиентское сообщение должно доходить до сервера с именем пользователя и сообщением в буфере, поэтому я использую strcpy(buffer, name) и strcat(buffer, ": ") для объединения буфера и имени. После этого я использую

n = write (sockfd, buffer, strlen(buffer))

для отправки буфера на сервер. Вот тут-то и происходит странная вещь, мой сервер ничего не показывает, но после этого при использовании

n = read(sockfd, buffer, 255);
printf("%s", buffer);

строка передана правильно. Вот мой код сервера:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ctype.h>

int main(){
    int port;
    int i = 1;
    printf("Enter port ->");
    scanf("%d", &port);

    int sockfd, newsockfd, n;
    char buffer[255];
    struct sockaddr_in6 serv_addr, cli_addr;
    int ret, flag;

    sockfd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 
    if (sockfd < 0){
        printf("Error opening socket\n");
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));
    flag = 1;
    ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
    if (ret < 0){
        printf("Set sock opt errror\n");
    }
    serv_addr.sin6_family = AF_INET6;
    serv_addr.sin6_addr = in6addr_any;
    serv_addr.sin6_port = htons(port);

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
        printf("Error binding\n");
    }

    listen(sockfd, 5);
    int clilen = sizeof(cli_addr);
    int pid;

    while(1){
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0){
            printf("Error on accept\n");
        }
        printf("New connection\n");
        pid = fork();
        if (pid < 0){
            printf("Error on pid\n");
        }
        if (pid == 0){
            close(sockfd);
            while(1){
                bzero(buffer, 255);
                n = read(newsockfd, buffer, 255);
                if (n < 0){
                    printf("Error on reading\n");
                }
                printf("%s", buffer);
                n = write(newsockfd, buffer, strlen(buffer));
                if (n < 0){
                    printf("Error on writing\n");
                }
            }
        } 
    }
    close(newsockfd);
    return 0;
}

и код клиента:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

int main(){

    int port;
    printf("Enter port ->");
    scanf("%d", &port);
    char ip[10];
    printf("Enter ip -> ");
    scanf("%s", &ip);
    char name[20];
    printf("Enter name -> ");
    scanf("%s", &name);
    int sockfd, n;
    char buffer[255];
    struct sockaddr_in6 serv_addr;

    sockfd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 
    if (sockfd < 0){
        printf("Error opening socket\n");
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin6_family = AF_INET6;
    inet_pton(AF_INET6, "ip", &serv_addr.sin6_addr);
    serv_addr.sin6_port = htons(port);
    if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
        printf("Connection failed\n");
    }

    while(1){

        bzero(buffer, 255);
        fgets(buffer, 255, stdin);
        strcpy(buffer, name);
        strcat(buffer, ": ");
        n = write (sockfd, buffer, strlen(buffer));
        bzero(buffer,255);
        if (n < 0){
            printf("Error on writing\n");
        }
        n = read(sockfd, buffer, 255);
        printf("%s", buffer);
        if (n < 0){
            printf("Error on reading\n");
        }
    }

    close(sockfd);
}

Так, может быть, кто-то может увидеть проблему, почему клиент не может отправить полный буфер с именем и сообщением на сервер? Я думаю, что проблема что-то с name. Когда я отправляю только тот буфер, который получаю, используя

fgets(buffer, 255, stdin);

сервер работает нормально, но мне нужно имя пользователя клиента.

Я пытался проверить strlen(name) и buffer, и все, кажется, в порядке. Я попытался вручную преобразовать имя в буфер следующим образом:

 for (int i = 0; i < strlen(name); i++){
        buffer[i] = name[i];
 }

Но тогда, если это единственный способ сделать это, как мне сдвинуть буфер вправо от введенного имени и не потерять информацию сообщения?

1 Ответ

2 голосов
/ 18 марта 2019

В вашем коде много ошибок:).

Прежде всего scanf принимает в качестве 1-го аргумента указатель, поэтому, когда вы хотите использовать его для строки, выполните:

char ip[10];
...
scanf("%s", ip);//THIS IS CORRECT

не scanf("%s", &ip);.

На сервере компилятор жаловался на тип clilen. accept ожидает sockelen_t (или эквивалентно unsigned int), пока вы объявили эту переменную как простой int.


Основная проблема

Это следующее. В клиенте вы сделали strcpy(buffer, name);, который копирует name, начиная с начала буфера, но начало буфера фактически содержало ваши данные. Вы должны сделать что-то вроде следующего, используя strcat, как вы сделали в следующей строке:

    bzero(buffer, 255);
    fgets(buffer, 255, stdin);
    strcat(buffer, name);
    strcat(buffer, ": ");

Дополнительные общие советы

Также обратите внимание на другое: не смешивайте функции системного вызова read write getchar с библиотечными функциями, такими как fread, fwrite, fgets. У меня была эта проблема с той причиной, что fgets мог прочитать больше байтов, чем ожидалось. В вашем случае все должно быть в порядке, потому что вы используете их для разных целей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...