【问题标题】:Identifying the messages from clients in multiple client single server program implemented in C在用 C 实现的多客户端单服务器程序中识别来自客户端的消息
【发布时间】:2013-07-15 14:11:05
【问题描述】:

我是网络的初学者。我使用 C 中的套接字实现了一个多客户端单服务器程序。如果我运行服务器和两个或更多客户端实例,那么我如何识别已向服务器发送消息的客户端。这个实现是正确的还是我必须修改它?

    //server.c
    #include <stdio.h>
    #include <sys/types.h>        
    #include <sys/socket.h>
    #include <strings.h>
    #include <arpa/inet.h>
    #include<netinet/in.h>
    #include<stdlib.h>
    #include<unistd.h>
    #define MAX 1000

    void serveClient(int sock)
    {
        int r;
            char buffer[MAX];
        do
        {
            bzero(buffer, sizeof(buffer));
                r = read(sock, buffer, sizeof(buffer));
            if(strcasecmp(buffer,"bye")==0) return;
            if(r != 0)
                printf("\nMessage from client : %s\n",buffer);
        }while(1);
    }

    int main()
    {
        int sockfd, newfd, len, r, pid;
        char buff[MAX];
        struct sockaddr_in servaddr,cliaddr;

        //creating socket
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            perror("socket");
            exit(1);
        }
        else
            printf("\nSocket created\n");   

        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(7790);
        servaddr.sin_addr.s_addr = INADDR_ANY;

        //bnding a name to socket
        if(bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) 
        {
            perror("bind");
            exit(1);
        }
        else
            printf("\nBind successful\n");

        //listening for connections
        if(listen(sockfd, 5) < 0)
        {
            perror("listen");
            exit(1);
        }
        else
            printf("\nListening...\n");

        //accepting a connection
        do
        {
            len = sizeof(cliaddr);
            if((newfd = accept(sockfd, (struct sockaddr*)&cliaddr, &len)) < 0) 
            {
                perror("accept");
                exit(1);
            }
            else
                printf("\nNew connection accepted\n");

            pid = fork();
            if(pid == -1)
            {
                perror("fork");
                close(newfd);
                continue;
            }
            else if(pid == 0)
            {
                serveClient(newfd);
                close(newfd);
                printf("\nClient terminated\n\nWaiting for new client...\n");
            }
            else 
            {
                close(newfd);
            }
        }while(1);
        close(sockfd);
        return 0;
    }


    //client.c
    #include <stdio.h>
    #include <sys/types.h>        
    #include <sys/socket.h>
    #include <strings.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include<stdlib.h>
    #define MAX 1000

    int main(int argc, char *argv[])
    {
        int len, sockfd, n;
        char buff[MAX];
    ;   struct sockaddr_in servaddr, cliaddr;
        if(argc == 2)
        {
            //creating socket
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            perror("socket");
            exit(1);
        }
        else
            printf("\nSocket created\n");

        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(7790);
        servaddr.sin_addr.s_addr = inet_addr(argv[1]);

        //initiating connection on the socket
        if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0) 
        {
            perror("connect");
            exit(1);
        }
        else
            printf("\nConnected\n");

        //sending message
        printf("\nType \"bye\" to disconnect\n");
        do
        {
            printf("\nMessage : ");
            scanf("%s",buff);
            n = write(sockfd, buff, sizeof(buff));
            if(strcasecmp(buff, "bye") == 0) exit(0);
        }while(1);
        close(sockfd);
    }
    else 
    {
        printf("\nSpecify an IP address\n");
        exit(1);
    }
    return 0;
}

【问题讨论】:

  • 使用socket()的返回值来知道谁给你发送了数据。

标签: c sockets client-server


【解决方案1】:

有很多书说,当您在基于 unix 的操作系统上拥有服务器客户端架构时,让 hte 操作系统完成所有艰苦的工作。当他们这么说时,他们的意思是让您的主线程在客户端上侦听套接字。当客户端进来时,接受 hte 连接并将用 accept 创建的新套接字分叉到新线程/进程(使用线程,实际上不是进程,所以不要使用 fork,而是使用 pthreads)。然后让该线程处理该客户端,您可以根据为其提供服务的线程来区分客户端。

您似乎正在执行 fork 实现。虽然这似乎是个好主意,但请记住,除非您使用 exec 重新加载程序映像,否则您的孩子将与您的父母拥有相同的内存占用。使用线程是一个更好的主意,这样您就只有一个程序映像,并且每个客户端连接的开销都更少。通过让线程池在信号量上等待,然后在连接上释放一个,您可以创建更少的开销。将您接受的新文件描述符保存在您可以跟踪的数组中。如果你的线程用完了,你可以让一个做多个客户端,或者只是创建另一个线程来处理涌入!然后你可以稍后销毁它们。

您也可以只创建包含客户端数据的通信协议,这样您就可以知道谁在说什么。唯一的问题是您必须扫描每个数据包以找出它属于哪个客户端,并将其存储直到您获得整个消息(如果它不能全部放入一个数据包中)。它只是更容易使用接受,移交的 pthread 模型。这样,您可以通过线程的 threadid 识别每个客户端。

【讨论】:

  • 当然你是对的,fork()ing 比使用线程造成更多的开销。另一方面,当每个服务器实例都是一个单独的进程时,您就消除了任何意外情况都可能导致整个服务器崩溃的危险,所以我想说一般人无法判断什么更好
  • 虽然您是对的,但 Windows (IIS) 和 Apache 的实现都使用线程模型而不是分叉模型来提高性能。但是,随之而来的是那些讨厌的挂线等,所以你是对的。
  • 谢谢..实际上这是我在计算机网络中的第一个程序,所以我不知道使用 pthread 库来实现该程序。无论如何,我会在了解它之后尝试。谢谢!!
【解决方案2】:

如果我运行服务器和两个或多个客户端实例,那么我如何识别向服务器发送消息的客户端。

每个客户端都由 accept() 返回的唯一文件描述符标识。您可以使用getpeername() 从文件描述符中获取客户端的地址和端口号。

在实际应用程序中,当accept() 成功并且客户端的文件描述符通常是该结构的成员时,服务器会在分配的结构中保留更多客户端状态。换句话说,与客户端连接相关联的结构是从服务器的角度来看的客户端。这样在客户端断开连接时很容易清理——只需释放结构并关闭文件描述符(或者,更好的是,使用 C++ 析构函数)。

【讨论】:

    猜你喜欢
    • 2017-06-18
    • 2013-02-25
    • 1970-01-01
    • 1970-01-01
    • 2013-03-18
    • 2014-02-19
    • 1970-01-01
    • 2014-02-28
    • 1970-01-01
    相关资源
    最近更新 更多