Сервер SCTP не может отправить сообщение по каналам клиенту - PullRequest
0 голосов
/ 10 февраля 2020

Сервер получает сообщения от клиента, но при отправке обратно клиенту по 3 каналам функция sctp_recvmsg возвращает -1. Иногда, когда я бегу, это работает, но это происходит через раз. Ребята помогите разобраться!

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

Сервер

  #include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <thread>
#include <vector>

using namespace std;

vector<thread> threadPool;

void multichatThread(int newsock, int flags)
{

  char buffer[512];

  printf("Новый клиент!\n");
  struct sctp_sndrcvinfo sndrcvinfo; // информация о пересылке
  if (sctp_recvmsg(newsock, (void *)buffer, sizeof(buffer), (struct sockaddr *)NULL, 0, &sndrcvinfo, &flags) == -1)
  { // принимаем сообщение от клиента
    printf("Error sctp_recvmsg!\n");
    return;
  }
  printf("%s\n", buffer);
  int i;
  for (i = 0; i < 3; i++)
  { // по всем 3-м потокам отправляем информацию
    if (sctp_sendmsg(newsock, (void *)buffer, (size_t)strlen(buffer), NULL, 0, 0, 0, i, 0, 0) == -1)
    { // отправляем клиенту сообщение
      int ec = errno;
      printf("Error sctp_recvmsg %d - %s!\n", ec, strerror(ec));
      return;
    }
  }
  close(newsock); // закрываем связь с клиентом
}

void createServer()
{
  struct sockaddr_in server, client;
  int sock;
  // создание сокета
  if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1)
  {
    printf("Error create socket!\n");
    return;
  }
  // структура для сервера
  server.sin_family = AF_INET;
  server.sin_addr.s_addr = htonl(INADDR_ANY); // локальный адрес
  server.sin_port = htons(0);                 // порт сервера
  // связка
  if (bind(sock, (struct sockaddr *)&server, sizeof(server)) == -1)
  {
    printf("Error bind!\n");
    return;
  }
  // настройка канала
  struct sctp_initmsg initmsg;
  initmsg.sinit_num_ostreams = 3;  // входные потоки
  initmsg.sinit_max_instreams = 3; // выходные потоки
  initmsg.sinit_max_attempts = 2;  // максимальное количество попыток
  setsockopt(sock, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));

  // объявляем очередь
  if (listen(sock, 5) == -1)
  {
    printf("Error listen!\n");
    return;
  }
  struct sockaddr_in sin;
  socklen_t len = sizeof(sin);
  if (getsockname(sock, (struct sockaddr *)&sin, &len) == -1)
    perror("getsockname");
  else
  {
    printf("Сервер создан!\n");
    printf("IP:  %s\n", inet_ntoa(sin.sin_addr));
    printf("Port: %d\n", ntohs(sin.sin_port));
  }

  int newsock;
  int clnlen = sizeof(client), flags;
  while (true)
  {
    if ((newsock = accept(sock, (struct sockaddr *)&client, (socklen_t *)&clnlen)) == -1)
    {
      printf("Error accept!\n");
      return;
    }

    thread chatThread(multichatThread, newsock, flags);
    chatThread.detach();
    threadPool.push_back(move(chatThread));
  }
  close(sock); // закрываем сокет сервера
}

int main()
{
  createServer();
  return 0;
}

Клиент получает порт и подключается к сервер. Затем он отправляет сообщение на сервер и ожидает ответа от сервера по трем каналам.

Клиент

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

using namespace std;

void connectServer(string ip, uint16_t port)
{
  // настройка структуры для сервера
  struct sockaddr_in server;
  server.sin_addr.s_addr = inet_addr("127.0.0.1");
  server.sin_family = AF_INET;
  server.sin_port = htons(port);
  // создаем сокет
  int sock;
  if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1)
  {
    printf("Error create!\n");
    return;
  }
  // настройка канала
  struct sctp_initmsg initmsg;
  memset(&initmsg, 0, sizeof(initmsg));
  initmsg.sinit_num_ostreams = 3;  // выходные потоки
  initmsg.sinit_max_instreams = 3; // входные потоки
  initmsg.sinit_max_attempts = 2;  // количество попыток
  setsockopt(sock, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));

  struct sockaddr_in sin;
  socklen_t len = sizeof(sin);

  printf("Данные о сокете!\n");
  printf("IP:  %s\n", inet_ntoa(server.sin_addr));
  printf("Port: %d\n", ntohs(server.sin_port));

  // соединяемся с сервером
  if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == -1)
  {
    printf("Error connect!\n");
    return;
  }
  // отправка и прием сообщения
  char buf[512] = "Hello!";
  if (sctp_sendmsg(sock, (void *)buf, (size_t)strlen(buf), NULL, 0, 0, 0, 1 /* номер потока */, 0, 0) == -1)
  {
    printf("Ошибка отправки пакета к серверу!\n");
    return;
  }
  struct sctp_sndrcvinfo sndrcvinfo;
  int i, flags;
  char buff[512];
  for (i = 0; i < 3; i++)
  { // по 3-м каналам принимаем сообщения
    bzero((void *)&buff, sizeof(buff));
    if (sctp_recvmsg(sock, (void *)buff, sizeof(buff), (struct sockaddr *)NULL, 0, &sndrcvinfo, &flags) == -1)
    {

      printf("Ошибка отправки пакета от сервера!\n");
      return;
    }
    printf("Сервер: %s\n", buff);
  }
  close(sock);
}
int main()
{

  string ip;
  uint16_t port;
  cout << "Введите IP:";
  cin >> ip;
  cout << "Введите PORT:";
  cin >> port;

  connectServer(ip, port);

  return 0;
}

1 Ответ

0 голосов
/ 10 февраля 2020

Сначала проверьте значение errno при ошибке - это может помочь.

if (sctp_recvmsg(newsock, (void *)buffer, sizeof(buffer), (struct sockaddr *)NULL, 0, &sndrcvinfo, &flags) == -1)
{
  int ec = errno;
  printf("Error sctp_recvmsg %d - %s!\n", ec, strerror(ec));
  return;
}
...