【问题标题】:how to connect two clients through a server using fork()如何使用 fork() 通过服务器连接两个客户端
【发布时间】:2014-12-05 10:54:24
【问题描述】:

我想创建一个邮件服务器。服务器一次连接两个客户端。当两个客户端连接时,每个客户端可以交替输入文本和读取另一个客户端编写的文本。服务器将在两个客户端中显示以下消息:

client 1 said : .......
what is your answer?
.....
....

我试图弄清楚如何在两个客户端之间建立连接,我所能做的就是在服务器和客户端之间进行通信(发送和接收文本),但我不知道如何通过服务器(我必须在此任务中使用 FORK())。 任何帮助将不胜感激

这里是服务器的代码:

#include  "unistd.h"
#include "errno.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "netdb.h"

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "strings.h"
#include "sys/wait.h"


    //Function Prototypes
    void myabort(char *);

    //Some Global Variables
    int serverport = 3000;
    char * eptr = NULL;
    int listen_socket, client_socket;
    struct sockaddr_in Server_Address, Client_Address;
    int result,i;
    socklen_t csize;
    pid_t processid;
    int childcount = 0;


    //main()
    int
    main(int argc, char **argv){

    char buf[100];
    char tmp[100];
          char * ptr;
         int n, sent, length;

        //Step 0: Process Command Line
         if (argc > 2){
             myabort("Usage: server ");
         }
        if (argc == 2){
             serverport =  (int) strtol(argv[1], &eptr, 10);
               if (*eptr != '\0') myabort("Invalid Port Number!");
          }

    //Step 1: Create a socket
          listen_socket = socket(PF_INET, SOCK_STREAM, 0);
          if (listen_socket == -1) myabort("socket()");


      //Step 2: Setup Address structure
         bzero(&Server_Address, sizeof(Server_Address));
          Server_Address.sin_family = AF_INET;
          Server_Address.sin_port = htons(serverport);
          Server_Address.sin_addr.s_addr = INADDR_ANY;


     //Step 3: Bind the socket to the port
          result = bind(listen_socket, (struct sockaddr *) &Server_Address, sizeof(Server_Address));
          if (result == -1) myabort("bind()");

    //Step 4:Listen to the socket
          result = listen(listen_socket, 1);
         if (result == -1) myabort("listen()");



    printf("\nThe forkserver :%d\n",ntohs(Server_Address.sin_port));
        fflush(stdout);
     //Step 5: Setup an infinite loop to make connections
        while(1){


    //Accept a Connection
             csize = sizeof(Client_Address);
               client_socket = accept( listen_socket,(struct sockaddr *) &Client_Address,&csize);
            if (client_socket == -1) myabort("accept()");

              printf( "\nClient Accepted!\n" );


            //fork this process into a child and parent
              processid = fork();

               //Check the return value given by fork(), if negative then error,
              //if 0 then it is the child.
              if ( processid == -1){
                  myabort("fork()");
            }else if (processid == 0){
                  /*Child Process*/

                close(listen_socket);
                  //loop until client closes
                 while (1){



                    //read string from client
                    bzero(&buf, sizeof(buf));
                    do{
                        bzero(&tmp, sizeof(tmp));
                        n = read(client_socket,(char *) &tmp, 100);
                        //cout << "server:  " << tmp;
                        tmp[n] = '\0';
                        if (n == -1) myabort("read()");
                        if (n == 0) break;
                        strncat(buf, tmp, n-1);
                        buf[n-1] = ' ';
                    } while (tmp[n-1] != '\n');

                    buf[ strlen(buf) ] = '\n';

                printf( "From client: %s",buf);

                    if (n == 0) break;


                     //write string back to client
                    sent = 0;
                    ptr = buf;
                      length = strlen(buf);

                    //the vowels in the message are converted into upper case.
                    for( i = 0; ptr[ i ]; i++)
                    {
                        if( ptr[i]=='a' ||  ptr[i]=='e' ||  ptr[i]=='i' || ptr[i]=='o' ||  ptr[i]=='u' )
                                 ptr[ i ] = toupper(  ptr[ i ] );
                        else
                             ptr[ i ] = ptr[ i ] ;

                    }   


                    printf( "To client: %s",ptr);
                    while (sent < length ){
                        n = write(client_socket, ptr, strlen(ptr) );
                        if ( n == -1) myabort("write()");
                        sent += n;
                        ptr += n;
                    }
                }//end inner while

                close(client_socket);

                //Child exits
                exit(0);
             }


              //Parent Process

            printf("\nChild process spawned with id number:  %d",processid );
            //increment the number of children processes
            childcount++;
            while(childcount){
                processid = waitpid( (pid_t) - 1, NULL, WNOHANG );
                if (processid < 0) myabort("waitpid()");
                else if (processid == 0) break;
                 else childcount--;
            }   

        }
        close(listen_socket);

        exit(0);

    }


    void myabort(char * msg){
        printf("Error!:  %s" ,  msg);
        exit(1);
    }

客户:

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "sys/socket.h"
#include "sys/types.h"
#include "netinet/in.h"
#include "strings.h"
#include "arpa/inet.h"

#define BUFFER    1024


main(int argc, char **argv)
{
    struct sockaddr_in serv;
    int sock;
    char in[BUFFER];
    char out[BUFFER];
    int len;


    if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket");
        exit(-1);
    }

    serv.sin_family = AF_INET;
    serv.sin_port = htons(atoi(argv[2]));
    serv.sin_addr.s_addr = inet_addr(argv[1]);
    bzero(&serv.sin_zero, 8);

    printf("\nThe TCPclient %d\n",ntohs(serv.sin_port));
        fflush(stdout);


    if((connect(sock, (struct sockaddr *)&serv, sizeof(struct sockaddr_in))) == -1)
    {
        perror("connect");
        exit(-1);
    }

    while(1)
    {
        printf("\nInput: ");

        fgets(in, BUFFER, stdin);
        send(sock, in, strlen(in), 0);


        len = recv(sock, out, BUFFER, 0);
        out[len] = '\0';
        printf("Output: %s\n", out);
    }

    close(sock);


}

【问题讨论】:

    标签: c sockets fork


    【解决方案1】:

    两个客户端相互交谈的一种方式是:accept 在你 fork 子进程之前两次,这样两个进程就可以相互认识。

    让服务器使用客户端 B 的 UNIX 域套接字文件描述符发送到 A 和 A 到 B,因为服务器知道两个客户端的 fd。检查这个unix域套接字(Sending file descriptor over UNIX domain socket, and select()

    使用服务器作为中间人:

    A write to server
    Server write to B whild B read from server
    B write to server while server read from B
    Server write to A while A should read from server
    

    【讨论】:

    • 是的,我以前也想过,但我不知道具体如何编码。我知道如何连接服务器和一个客户端,但问题是如何让客户端 2 参与其中(如何使服务器写入客户端 2 而不是写回客户端 1)
    • 您好,我已经尝试接受两次并且成功了,但是有一个大问题:我需要两个客户端同时写入和接收如何同步两个客户端。当我运行程序时,两个客户端都在等待来自服务器的数据如何编辑客户端代码,以便一个必须等​​待另一个正在写入的数据????
    • 在服务器中创建一个新线程并处理消息。当您的线程正在处理您的服务器可以处理新客户端的消息时
    【解决方案2】:

    几天前我为相同的场景编写了一个代码。仍然不正确,但它工作得很好,可以让你领先一步

    服务器端代码:-

     #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/socket.h>
    #include<arpa/inet.h>
    #include<unistd.h>
    #include<signal.h>
    #include<sys/wait.h>
    
    
    static void   sigchld_handler(int signo) {  
        pid_t PID;   
        int status;  
    
      do {  
         PID = waitpid(-1,&status,WNOHANG);  
          }   
      while ( PID != -1 );  
    

    // 恢复处理程序

      signal(SIGCHLD,sigchld_handler);  
    

    }

      int main(int argc ,char *argv[])
    { 
       int server_socket; 
        int client_socket , size_structure,read_size,binds;
        int *new_socket;
        struct sockaddr_in server, client ;
        server_socket = socket(AF_INET, SOCK_STREAM,0);
        char client_message[100]="";
         pid_t PID;                    /* Process ID */  
    

    /* * 为 SIGCHLD 设置信号处理程序: */
    信号(SIGCHLD,sigchld_handler);

        if(server_socket == -1)
        {  
            puts("socket has nt been created");
        }
        else 
            puts("socket has been created");
    
        //give values to the structure for server
     server.sin_family = AF_INET;
     server.sin_addr.s_addr = INADDR_ANY;
        server.sin_port = htons(2225);
    
    //step 3 bind karo 
    binds = bind(server_socket,(struct sockaddr*)&server,sizeof(server));
    
    if(binds<0)
        {
        perror("bind failed.Error");
        return 1;
        } 
        puts("SOcket has been binded to address");
    
    //listen to incoming request
    
    listen(server_socket,30); 
    size_structure = sizeof(struct sockaddr_in);
    FILE *fp;
    fp =fopen("test.txt","w");
    
    while (1)
        {
    
        client_socket = accept(server_socket,(struct sockaddr *)&client,(socklen_t*)&size_structure);
         if(client_socket<0)
            { 
                puts("client is nt connected");
            return 1;
            }
        else 
            puts("connection accepted");
    
        if((PID = fork())== -1)
            { 
                close(client_socket);
                continue;
            }
    
        else if(PID >0)
            {
            close(client_socket);
            continue;
            }
    
        setlinebuf(fp);
    
        while(( read_size=recv(client_socket,client_message,2000,0))>0)
            {
    
            puts(client_message);
                write(client_socket,client_message,sizeof(client_message));
            for(int i=0;i<500;i++)
                { 
                fwrite(client_message,1,sizeof(client_message),fp);
                } 
            if(PID==-1)
                {  
                exit(0);
                }
            memset(client_message,0,strlen(client_message));
    
            }
    
        if(read_size==-1)
            {
            puts("client disconnected");
            fflush(stdout);
            close(client_socket);
            exit(0);
            }
        else if(read_size == 0)
            { 
                printf("recveiving failed");
                }
        }
    
    
    
    memset(client_message,0,strlen(client_message));
    close(client_socket);
    fclose(fp);
    return 0;
    

    }

    客户端代码:-

       #include<stdio.h>
       #include<sys/socket.h>
       #include<arpa/inet.h>
       #include<string.h>
     #include<sys/types.h>
    
    
     int main()
    {
    
     struct sockaddr_in myaddr ,serveraddr;
     int sockid;
     sockid=socket(AF_INET,SOCK_STREAM,0);
     memset(&myaddr,'0',sizeof(myaddr));
     myaddr.sin_family=AF_INET;
     myaddr.sin_port=htons(8888);
     myaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
     if(sockid==-1)
     {
        perror("socket");
     }
     int len=sizeof(myaddr);
     if(connect(sockid,(const struct sockaddr*)&myaddr,len)==-1)
     {
        perror("connect");
     }
     fprintf(stdout,"Client Online....");
     char s[10000];
    
    
        //gets(s);
        //send(sockid,s,10000,0);
        recv(sockid,&s,10000,0);
        fprintf(stdout,"Server says....");
        puts(s);
        recv(sockid,&s,10000,0);
        fprintf(stdout,"Server says....");
        puts(s);
    
     sleep(10);  
     close(sockid);
     return 0;
    }
    

    【讨论】:

      【解决方案3】:

      我认为您必须通过服务器注册您的客户端并将其套接字描述符存储在某种数组中。每个客户端都应该有一个唯一的标识符。还要指定某种协议,其中包含一些信息,如发送者、目的地(=client1 或 2)和消息。您的服务器可以处理消息并将您的消息路由到目的地。

      协议可以很简单,比如

      发件人|收件人|消息

      例如

      client-1|client-2|来自客户端 1 的问候

      您也可以使用一些 xml 或任何其他类型的数据结构

      在服务器端。将消息提取为 3 个字符串部分 string-1 : 发件人 (client-1) string-2 : 目的地 (client-2) 字符串 3:消息(来自客户端 1 的问候

      服务器可以将消息(即字符串 3)发送到客户端 2

      【讨论】:

      • 但是发送和接收消息时如何交换ID,我在这里很困惑!!!!!!
      • client-1 向目标 client-2 发送消息,反之亦然。您还可以决定服务器向所有连接的客户端(发送的客户端除外)广播客户端消息
      • 您的服务器必须包含已连接客户端的列表
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-08
      • 2017-05-08
      • 2011-11-05
      相关资源
      最近更新 更多