SCTP服务器无法通过通道向客户端发送消息

时间:2020-02-10 13:01:59

标签: c sockets server sctp

服务器从客户端接收消息,但是当通过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 :(得分:0)

首先,检查错误时的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;
}