Nano Hash - криптовалюты, майнинг, программирование

Использование printf с потоками и программирование сокетов

Я делал сервер, используя программирование сокетов, которое повторяет то, что говорит ему клиент. Но когда я распечатываю сообщение (отправленное клиентом) и его длину, сообщение и его длина не совпадают. Я использую printf для печати.

В основном я хочу закрыть соединение, когда клиент набирает «выход». Но strcmp("exit",clientmessage) не работает.

код сервера:

//for running type ./a.out anyportnumber
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

void *function(void *s)
{
    int s1;
    int n;
    char rmsg[500];
    s1 = *(int *)s;
    while((n = read(s1,rmsg,499)) > 0) {
        rmsg[n] = '\0';
        printf("%s %d\n",rmsg,strlen(rmsg));
        bzero(rmsg,499);
    }
    pthread_exit(NULL);
}
int main(int arrc,char *argv[])
{
    struct sockaddr_in server,client;
    int s1,len;
    int s2;
    int n;
    int i = 0;
    int port;
    pthread_t t1;
    char message[500];
    port = atoi(argv[1]);
    bzero((char *)&server,sizeof(server));
    server.sin_port = htons(port);
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_family = AF_INET;
    s1 = socket(AF_INET,SOCK_STREAM,0);
    if(s1 == -1) {
        perror("socket not created\n");
        exit(1);
    }
    if(bind(s1,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
        perror("socket not binded\n");
        exit(1);
    }
    if(listen(s1,5) == -1) {
        perror("unable to listen");
        exit(1);
    }
    len = sizeof(struct sockaddr_in);
    s2 = accept(s1,(struct sockaddr *)&client,&len);
    pthread_create(&t1,NULL,function,(void *)&s2);
    pthread_join(t1,NULL);
    close(s2);
    close(s1);
    return 0;

}

ввод на стороне клиента:

shivam@shivam-HP-Pavilion-15-Notebook-PC:~$ telnet localhost 8009
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hhh
jhiklmnop

Вывод на стороне сервера:

shivam@shivam-HP-Pavilion-15-Notebook-PC:~/Study/chat$ ./a.out 8009
hhh
 5
jhiklmnop
 11

Отредактированный код:

//for running type ./a.out anyportnumber
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
void *function(void *s)
{
    int s1;
    int n;
    char rmsg[500];
    s1 = *(int *)s;
    char d[] = {'e','x','i','t','\0'};
    while((n = read(s1,rmsg,499)) > 0) {
        rmsg[n-2] = '\0';
        if(strcmp(d,rmsg) == 0) {
            write(s1,"bye",3);
            close(s1);
        }
        rmsg[n-2] = '\n';
        rmsg[n-1] = '\0';
        write(s1,rmsg,strlen(rmsg));
        bzero(rmsg,499);
    }
    pthread_exit(NULL);
}
int main(int arrc,char *argv[])
{
    struct sockaddr_in server,client;
    int s1,len;
    int s2;
    int n;
    int i = 0;
    int port;
    pthread_t t1;
    char message[500];
    port = atoi(argv[1]);
    bzero((char *)&server,sizeof(server));
    server.sin_port = htons(port);
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_family = AF_INET;
    s1 = socket(AF_INET,SOCK_STREAM,0);
    if(s1 == -1) {
        perror("socket not created\n");
        exit(1);
    }
    if(bind(s1,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
        perror("socket not binded\n");
        exit(1);
    }
    if(listen(s1,5) == -1) {
        perror("unable to listen");
        exit(1);
    }
    len = sizeof(struct sockaddr_in);
    s2 = accept(s1,(struct sockaddr *)&client,&len);
    pthread_create(&t1,NULL,function,(void *)&s2);
    pthread_join(t1,NULL);
    close(s2);
    close(s1);
    return 0;

}
20.07.2016

Ответы:


1

TCP — это протокол, ориентированный на поток, в нем нет границ сообщений. Таким образом, вы не можете написать логику приложения, которая зависит от возвращаемого значения read(), как вы это делаете.

Обходными путями для этого являются строки с префиксом длины или отправка терминатора NUL через сокет. Можно придумать и другие механизмы, но клиент должен в потоке данных сообщать серверу, где заканчивается сообщение; уровень TCP этого не сделает.

20.07.2016
  • Для этого есть даже специальные значения ascii (обычно используемые в последовательных терминалах, но все же полезные и используемые). Я когда-то работал с устройством, которое их использовало. STX (0x02) для начала текста, и я думаю, что это был 0x03 для окончания текста. Таким образом, OP также может использовать эти неиспользуемые значения ascii. В настоящее время я работаю с сервером веб-сокетов, который отправляет списки Json, разделенные такими символами, а также использует STX. 20.07.2016
  • Конечно я знаю. Я вообще не очень понимаю, почему так сделано. Это служба в Интернете, которая не документирована или что-то в этом роде, и я просто сделал вывод о том, как вещи отправляются или принимаются в нее, чтобы работать с ней. Но это действительно странно. Поскольку вы можете определять массивы в чистом Json, вам не нужны разделители или специальные символы. Но так оно и есть. 20.07.2016
  • @BenVoigt Посмотрите на отредактированный код. Он работает нормально после того, как я удалил последние два символа. Будет ли это работать все время? 20.07.2016
  • @ShivamMitra: Нет, это ненадежно. Одна команда, такая как exit, может быть разделена на несколько вызовов чтения (например, вы получаете e из первого, а затем xit\r\n из второго — это действительно плохо, потому что теперь индекс n-2, где вы записываете символ NUL, отрицательный, и вы искажаете другой объект ) или вы можете получить более одной команды за один вызов чтения, например hello\r\nexit\r\n 20.07.2016

  • 2

    Помимо символов, которые вводит пользователь, вы также получаете символ возврата каретки (0xd) и перевода строки (0xa), когда пользователь нажимает клавишу Enter. Вот почему вы получаете число 2 больше, чем вы могли ожидать.

    20.07.2016
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..