как правильно использовать многопоточность и сокеты в c? - PullRequest
1 голос
/ 22 апреля 2020

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

Исходный код:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

#define PORT_CONN1 4444
#define PORT_CONN2 4445

char buf1[1024];
char buf2[1024];

int msg_1() {
  while(1) {
    recv(conn_1, &buf1, 1024, 0);
    send(conn_2, buf1, sizeof(buf1), 0);
  }
}

int msg_2() {
  while(1) {
    recv(conn_2, &buf2, 1024, 0);
    send(conn_1, buf2, sizeof(buf2), 0);
  }
}

int main() {
  int sockfd_1, sockfd_2, conn_1, conn_2;
  struct sockaddr_in host_addr, client_addr;
  socklen_t sin_size;
  int recv_length=1, ok=1;

  sockfd_1 = socket(PF_INET, SOCK_STREAM, 0);
  sockfd_2 = socket(PF_INET, SOCK_STREAM, 0);
  setsockopt(sockfd_1, SOL_SOCKET, SO_REUSEADDR, &ok, sizeof(int));
  setsockopt(sockfd_2, SOL_SOCKET, SO_REUSEADDR, &ok, sizeof(int));

  host_addr.sin_family = AF_INET;
  host_addr.sin_port = htons(PORT_CONN1);
  host_addr.sin_addr.s_addr = 0;
  memset(&(host_addr.sin_zero), "\0", 8);

  bind(sockfd_1, (struct sockaddr *)&host_addr, sizeof(struct sockaddr));

  host_addr.sin_family = AF_INET;
  host_addr.sin_port = htons(PORT_CONN2);
  host_addr.sin_addr.s_addr = 0;
  memset(&(host_addr.sin_zero), "\0", 8);

  bind(sockfd_2, (struct sockaddr *)&host_addr, sizeof(struct sockaddr));

  listen(sockfd_1, 5);
  listen(sockfd_2, 5);

  while(1) {
    pthread_t thread1, thread2;
    sin_size = sizeof(struct sockaddr_in);
    conn_1 = accept(sockfd_1, (struct sockaddr *)&client_addr, &sin_size);
    conn_2 = accept(sockfd_2, (struct sockaddr *)&client_addr, &sin_size);

    pthread_create(&thread1, NULL, msg_1, NULL);
    pthread_create(&thread2, NULL, msg_2, NULL);
    pthread_exit(NULL);

    close(conn_1);
    close(conn_2);
  }
}

1 Ответ

0 голосов
/ 22 апреля 2020

Я не знаю, что я сделал не так.

Некоторые подсказки.

Сначала ваша программа не может скомпилировать

  • в msg_1 и msg_2 вы используете conn_1 и conn_2, которые не определены (это локальные переменные в main)
  • второй аргумент memset должен быть int Указывая байт, используемый для установки блока памяти, вы даете массив char ("\0")
  • подпись msg_1 и msg_2 несовместимы с thread_create

Вы хотите обмениваться данными между двумя потоками через сокет (ы), вам не нужно использовать два сокета для этого, только один достаточно, потому что сокет является двунаправленным (в отличие от pipe ).

Чтобы иметь сокет , вам нужен сервер и клиент, один и тот же поток не может быть обоими, accept блокирует поток до тех пор, пока клиент не подключится. В вашей программе основной поток класс принимает , но нет подключенного клиента, поэтому вы окончательно заблокированы.

Факт окончания main в while довольно неясен. Это также относится к pthread_exit(NULL);, если вы используете эти функции, это в двух потоках , но не в main.

Обратите внимание, что используемый сокет - stream , это означает, что когда вы читаете на нем, вы не можете предположить что-то о количестве байтов, которые вы получаете. В этом разница с дейтаграммой .

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

Для упрощения я рекомендую вам сделать первую версию, где main является сервером, а единственный дополнительный поток является клиентом. Предупреждение не запускать дополнительный поток слишком рано или слишком поздно, то есть после listen, но до accept.

...