【问题标题】:SCTP server cannot send message over channels to clientSCTP 服务器无法通过通道向客户端发送消息
【发布时间】:2020-05-25 19:22:08
【问题描述】:

服务器接收到客户端的消息,但是通过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;
}

【问题讨论】:

  • sleep(10); - 嗯,为什么
  • 这一切看起来都非常像C。为什么问题标记为“c++”?
  • while(true) { … thread chatThread(multichatThread, newsock, flags); chatThread.detach(); } 这一切对我来说都是多线程不安全的,因为chatThread 是一个局部变量,在每次迭代时都会被销毁。 detach 需要在 thread 对象被销毁之前完成,您无法控制先完成哪个。
  • the sctp_recvmsg function returns -1 - 之后 errno 的值是多少? when sending back ... sctp_recvmsg - 你收到recvmsg,你的意思是用sendmsg发送? printf("%s\n", buffer); - 我认为您应该在此之前检查 flags 以获取 MSG_EOR。而且您的flags 用法似乎很糟糕,如果它未初始化,为什么还要将它传递给multichatThread
  • 感谢大家的回复!它似乎已经开始工作了 :) 没有你们,我无法做到,谢谢大家。

标签: c sockets server sctp


【解决方案1】:

首先,检查 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;
}

【讨论】:

  • 它起初可以工作,但后来:( 错误 sctp_sendmsg 11 - 资源暂时不可用!
猜你喜欢
  • 1970-01-01
  • 2023-03-08
  • 2011-05-12
  • 1970-01-01
  • 2022-11-29
  • 2018-07-05
  • 2023-04-03
  • 2012-01-18
相关资源
最近更新 更多