首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C中的多会话聊天服务器

C中的多会话聊天服务器
EN

Stack Overflow用户
提问于 2013-09-16 17:31:00
回答 2查看 1.5K关注 0票数 0

我试图用C语言编写一个多会话聊天服务器。我将服务器从一个终端托管到另一个终端。在VMWare播放器上使用ubuntu13.04。

所发生的事情是:

我将循环从3增加到fdmax,使用sd (侦听器)接受新的连接,newsd表示新的套接字描述符。

当我在一个窗口中打印“hi”时,它会在所有窗口中打印,包括我键入的窗口。另外,很多随机的垃圾不断出现。我只想看到我输入的内容(如何摆脱junk>),在所有的窗口中,除了我输入的窗口之外!

代码语言:javascript
复制
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netdb.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<sys/select.h>

void *get_in_addr(struct sockaddr *sa)
{
  if (sa->sa_family == AF_INET)
  {
    return &(((struct sockaddr_in*) sa)->sin_addr);
  }

  return &(((struct sockaddr_in6*) sa)->sin6_addr);
}

int main(int argc, char **argv)
{
  //ptr used for traversal, serv used for the linked list of struct addinfos , hints for      the getaddrinfo function
  struct addrinfo *ptr, hints, *serv;
  int max_cli, dat, x, i;
  struct sockaddr_storage cli_addr;
  socklen_t addr_size;
  char cli_ip[INET_ADDRSTRLEN];
  char inc[256]; //one command line is 80 characters
  memset(inc, 0, strlen(inc));
  int sd, newsd;
  fd_set master;
  fd_set read_fds;
  char value[256];

  FD_ZERO(&master);
  FD_ZERO(&read_fds);

  //argv[1]-server ip argv[2]-server port argv[3]-maximum client number

  int fdmax;
  int opt = 1;

  /*if(argc!=4)
   {
   printf("Please re-enter data. Data insufficient\n");
   exit(1);
   }
   if(atoi(argv[2])<1025)
   {
   printf("Reserved port. Please try again\n");
   exit(1);
   }*/
  max_cli = atoi(argv[3]);

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  /* Verify the inputs and generate linked list of possible IPs to use*/

  if (sd = getaddrinfo(argv[1], argv[2], &hints, &serv))
  {
    fprintf(stderr, "Error calling getaddrinfo %s\n", gai_strerror(sd));
    exit(1);
  }

  for (ptr = serv; ptr != NULL ; ptr = ptr->ai_next)
  {

    void *addr;
    if (ptr->ai_family == AF_INET)
    {
      struct sockaddr_in *ipv4 = (struct sockaddr_in *) ptr->ai_addr;
      addr = &(ipv4->sin_addr);
    }
    inet_ntop(ptr->ai_family, addr, value, sizeof value);
    //printf("%s\n",value);     

    //Form connection with one of the IP addresses   
    sd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
    if (sd < 0)
      continue;

    setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);

    if (bind(sd, ptr->ai_addr, ptr->ai_addrlen) < 0)
    {
      close(sd);
      continue;
    }

    break; //Indicates one working socket found and bound
  } //end for

  if (ptr == NULL )
  {
    fprintf(stderr, "Bind failed\n");
    exit(2);
  }

  freeaddrinfo(serv);

  if (listen(sd, 15) == -1)
  {
    printf("Error occurred while listening\n");
    exit(3);
  }

  /* Socket found, bound and now listening for active connections*/

  FD_SET(sd, &master);

  fdmax = sd; //Latest active socket descriptor

  while (1)
  {

    read_fds = master; //Copy the master list so that the original list doesn't get damaged

    if (select(fdmax + 1, &read_fds, NULL, NULL, NULL ) == -1)
    {
      perror("Select failed.\n");
      exit(4);
    }

    for (i = 3; i <= fdmax; i++)
    {
      //printf("i");
      //printf("entered for loop\n");
      if (FD_ISSET(i,&read_fds))    //new connection->false, existing one->true
      {
        //  printf("Started reading descriptors!\n");

        if (i == sd)    //primary connection,exists, accept new file descriptor
        { //printf("Read first connection!\n");
          addr_size = sizeof cli_addr;
          newsd = accept(sd, (struct sockaddr *) &cli_addr, &addr_size);
          printf("Accepted new connection socket %d\n", newsd);
          FD_SET(newsd, &master);
          if (newsd == -1)
          {
            perror("accept");
          }
          if (newsd > fdmax)
          {
            fdmax = newsd;
          }
          printf("%d %d\n", newsd, fdmax);
          continue;
        }
        else if (i != sd) //existing connection, so accept data
        {
          if (dat = recv(i, &inc, sizeof inc, 0) <= 0)
          {
            if (dat == 0)
            {
              printf(" Socket %d has quit the   chatroom", i);
            }
            if (dat < 0)
            {
              perror("Error on Receive");
            }
            //  char *s=&inc;
            //printf("%d\n %s",dat);
            close(i);
            FD_CLR(i, &master);
          }

          //Nothing wrong with the input from client i.  Broadcast!
          else
          {
            for (x = 3; x <= fdmax; x++)
            {
              if (FD_ISSET(x,&master))
              {
                if (x != sd)
                {
                  //send(x,&inc,sizeof inc,0);
                  if (send(x, &inc, sizeof inc, 0) < 0)
                  {
                    perror("Send");
                  }
                }
              }
            }
          }
        }

      }

      /*else// new connection
       { break;

       printf("SERVERBOT: new connection from %s on socket %d\n",inet_ntop(cli_addr.ss_family,get_in_addr((struct sockaddr*)&cli_addr),cli_ip, INET6_ADDRSTRLEN),newsd);
       }////change this to 'username' has joined the room*/

    }
  }

  return 0;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-09-16 19:08:59

首先,当您发送接收到的数据时,使用sizeof操作符,它为您提供了数组的总大小。您应该发送与收到的字节一样多的字节,这通常会更少。使用recv的返回值来知道实际接收的字节数。一般来说,C数组没有动态大小,您必须自己跟踪。

然后,关于垃圾,您可能打印缓冲区内容而不终止'\0'字符。所以,要么添加它(确保缓冲区中有1字节的额外空间!)在打印或使用其他字符串函数之前,或使用接受字符串最大大小的打印函数,以防缺少nul终止。

票数 1
EN

Stack Overflow用户

发布于 2013-09-16 20:22:20

作为一开始,您的发送必须使用dat作为长度不太大(Inc)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18833910

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档