C Sockets 客户端/服务器 pthreads 服务器广播

标签 c sockets server pthreads client

我们得到了这段代码,并应该对其进行修改,以便每当客户端连接到服务器并发送消息时,服务器都应该回复我听到你的声音了。这适用于一个或多个客户端,但下一个任务是每当有新客户端连接时,服务器就应将其告知所有其他已连接的客户端。

我以为这会相当容易,但它并不像我想象的那样有效。由于服务器总是获取 sock 3,第一个客户端获取 4,第二个客户端获取 5 等,我尝试创建一个 for 循环,每当新客户端连接时都会发送消息,该循环将发送消息到 4,5,这使服务器直接关闭自身。然后,我尝试在新客户端连接时,服务器应该向第一个客户端(4)发送消息,它实际上会这样做,但只有当客户端(4)向服务器写入一条消息时,他才会收到服务器发送的广播。

所以看起来客户端想要写,但需要在收到服务器的广播之前写一些东西,任何帮助将不胜感激,因为我们对这一切都是初学者。

这就是代码目前的样子。

服务器.c

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/times.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <pthread.h>

#define PORT 5555
#define MAXMSG 512


void *connection_handler(void *socket_desc)
{
    int sock = *(int*)socket_desc;
    int read_size;
    char *message, client_message[2000], *message_to_client;
    message = "Greetings! I am your connection handler\n";
    write(sock, message, strlen(message));
    while( (read_size = recv(sock, client_message, 2000, 0)) > 0)
    {
       client_message[read_size] = '\0';
       printf("Client[%d]: %s", sock, client_message);
       message_to_client = "I hear you dude...";
       write(sock, message_to_client, 19);
       memset(client_message, 0, 2000);
    }

    if(read_size == 0)
    {
       printf("Client[%d] disconnected", sock);
       fflush(stdout);
    }
    else if(read_size == -1)
    {
       perror("recv failed");

    }
    free(socket_desc);
    return 0;
}

int makeSocket(unsigned short int port) {
    int sock;
    struct sockaddr_in name;
    /* Create a socket. */
    sock = socket(PF_INET, SOCK_STREAM, 0);
    if(sock < 0) {
        perror("Could not create a socket\n");
        exit(EXIT_FAILURE);
    }
    name.sin_family = AF_INET;
    name.sin_port = htons(port);
    name.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) {
        perror("Could not bind a name to the socket\n");
        exit(EXIT_FAILURE);
    }
    return(sock);
}

int main(int argc, char *argv[])
{
    int sock;
    int clientSocket;
    int i;
    int *new_sock;
    char *broadcast;
    fd_set activeFdSet, readFdSet;
    struct sockaddr_in clientName;
    socklen_t size;
    sock = makeSocket(PORT);
    if(listen(sock,1) < 0) 
    {
        perror("Could not listen for connections\n");
        exit(EXIT_FAILURE);
    }
    FD_ZERO(&activeFdSet);
    FD_SET(sock, &activeFdSet);
    while(1) 
    {
        printf("Waiting for connections\n");
        readFdSet = activeFdSet;
        if(select(FD_SETSIZE, &readFdSet, NULL, NULL, NULL) < 0)
        {
            perror("Select failed\n");
            exit(EXIT_FAILURE);
        }
        for(i = 0; i < FD_SETSIZE; ++i)
        {
            if(FD_ISSET(i, &readFdSet)) 
            {
                if(i == sock) 
                {
                    size = sizeof(struct sockaddr_in);
                    pthread_t sniffer_thread;
                    while(( clientSocket = accept(sock, (struct sockaddr *)&clientName, (socklen_t *)&size))) 
                    {
                        puts("Connection accepted");
                        new_sock = malloc(1);
                        *new_sock = clientSocket;
                        if( pthread_create( &sniffer_thread, NULL, connection_handler, (void*) new_sock) < 0)
                        {
                            perror("could not create thread");
                            return 1;
                        }
                        broadcast = "NEW CLIENT CONNECTED";
                        write(4, broadcast, sizeof(broadcast)); //just to see if when ever a new client connects the first client should get all these messages
                        write(4, broadcast, sizeof(broadcast));
                        write(4, broadcast, sizeof(broadcast));
                        pthread_detach(sniffer_thread);
                        puts("Handler assigned");
                        FD_SET(*new_sock, &activeFdSet);

                   }
                   if(clientSocket < 0) 
                   {
                       perror("Could not accept connection\n");
                       exit(EXIT_FAILURE);
                   }                
                }
                else 
                {
                    if(readMessageFromClient(i) < 0)
                    {
                    close(i);
                        FD_CLR(i, &activeFdSet);
                    }
                }
            }
        }      
    }
} 

对于客户端来说,代码如下所示

客户端.c

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define PORT 5555
#define hostNameLength 50
#define messageLength  256

void initSocketAddress(struct sockaddr_in *name, char *hostName, unsigned short int port) 
{
  struct hostent *hostInfo; 
  name->sin_family = AF_INET;
  name->sin_port = htons(port);
  hostInfo = gethostbyname(hostName);
  if(hostInfo == NULL)
  {
    fprintf(stderr, "initSocketAddress - Unknown host %s\n",hostName);
    exit(EXIT_FAILURE);
  }
  name->sin_addr = *(struct in_addr *)hostInfo->h_addr;
}
void writeMessage(int fileDescriptor, char *message) 
{
  int nOfBytes;
  nOfBytes = write(fileDescriptor, message, strlen(message) + 1);
  if(nOfBytes < 0) 
  {
    perror("writeMessage - Could not write data\n");
    exit(EXIT_FAILURE);
  }
}

int main(int argc, char *argv[]) 
{
  int sock;
  struct sockaddr_in serverName;
  char hostName[hostNameLength];
  char messageString[messageLength];
  char buffer[1024];
  if(argv[1] == NULL) 
  {
    perror("Usage: client [host name]\n");
    exit(EXIT_FAILURE);
  }
  else 
  {
    strncpy(hostName, argv[1], hostNameLength);
    hostName[hostNameLength - 1] = '\0';
  }

  sock = socket(PF_INET, SOCK_STREAM, 0);
  if(sock < 0) 
  {
    perror("Could not create a socket\n");
    exit(EXIT_FAILURE);
  }

  initSocketAddress(&serverName, hostName, PORT);
  if(connect(sock, (struct sockaddr *)&serverName, sizeof(serverName)) < 0) 
  {
    perror("Could not connect to server\n");
    exit(EXIT_FAILURE);
  }
  printf("\nType something and press [RETURN] to send it to the server.\n");
  printf("Type 'quit' to nuke this program.\n");
  fflush(stdin);
  recv(sock, buffer, 1024, 0);
  printf(buffer);
  while(1) 
  {
    printf("\n>");
      fgets(messageString, messageLength, stdin);
      messageString[messageLength - 1] = '\0';
      if(strncmp(messageString, "quit\n",messageLength) != 0)
         writeMessage(sock, messageString);
      if(recv(sock, buffer, 1024, 0) > 0)
               printf(buffer);


  }
}

最佳答案

您需要对代码进行一些更改才能使其正常工作。您没有收到任何内容的原因是您的客户陷入了

fgets(messageString, messageLength, stdin);这是一个阻塞调用,所以只需在客户端创建一个用于消息接收的线程,使其能够持续监听。对代码进行以下更改,它应该可以帮助您实现结果。

将以下行添加到代码的客户端:

客户端.c

void * receiveMessage(void * socket)
{
    int sockfd, ret;
    char buffer[1024];
    sockfd = (int) socket;
    int count = 1;
     memset(buffer, 0, 1024);
     for (;;)
     {
         if (recvfrom(sockfd, buffer, 1024, 0, NULL, NULL) > 0)
         {
             fputs(buffer, stdout);
             printf("\n");
         }
     }
}

在主函数中添加以下行

 //creating a new thread for receiving messages from the server
   read = pthread_create(&rThread, NULL, receiveMessage, (void *) sock);
   if (read < 0)
   {
       printf("ERROR: Return Code from pthread_create() is %d\n", read);
       exit(1);
   }

并将 while 循环更改为下面

 while(1)
  {
      printf("\n>");

      fgets(messageString, messageLength, stdin);

      messageString[messageLength - 1] = '\0';

      if(strncmp(messageString, "quit\n",messageLength) != 0)
      {
          writeMessage(sock, messageString);
      }
  }

Server.c(在连接处理程序中添加广播消息)

void *connection_handler(void *socket_desc)
{
    int sock = *(int*)socket_desc;
    int read_size;
    char *message, client_message[2000], *message_to_client;
    char broadcast[50] = "new client connected";
    int num;

    num = sock;
    num--;
    while(num > 3)
    {
        write(num, broadcast, strlen(broadcast));
        sleep(1);
        num--;
    }

    while((read_size = recv(sock, client_message, 2000, 0)) > 0)
    {
       client_message[read_size] = '\0';
       printf("Client[%d]: %s", sock, client_message);
       message_to_client = "I hear you dude...";
       write(sock, message_to_client, strlen(message_to_client));
       memset(client_message, 0, 2000);
    }

    if(read_size == 0)
    {
        printf("Client[%d] disconnected", sock);
        fflush(stdout);
    }
    else if(read_size == -1)
    {
        perror("recv failed");

    }

    free(socket_desc);
    return 0;
} 

关于C Sockets 客户端/服务器 pthreads 服务器广播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35381611/

相关文章:

c - 在Arduino IDE中将浮点值转换为科学记数法的语法?

c - 输出文件问题/不兼容的指针类型

java - 当socketChannel.read(BUFFER)将返回0时

javascript - Python本地服务器问题: rfile gets truncated when posting through ajax

windows - 在 SendGrid.Net 上使用 SmartHost 的 IIS SMTP

c - 二叉搜索树删除不起作用,为什么?

c - 错误: null parameter when calling GRBloadmodel

C#、异步套接字服务器/客户端、StackOverflowException

c - 接收/接收的最大镜头数是多少

java - 客户端一打开,服务器端就关闭