C语言 使用 fork() 的多客户端服务器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13669474/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:38:59  来源:igfitidea点击:

Multiclient server using fork()

calgorithmsocketsunixfork

提问by user1724072

I am trying to create a socket programming server to handle multiple clients at the same time using fork().. But I am not able to implement it properly.I have been trying for a long time . The problems I am facing are 1) address bind problem 2) problem how to handle parent process and child process 3) how to end the server program ie ..return to the console My programs for a single client server were working properly.Here is my code for the multiple client-server.

我正在尝试使用 fork() 创建一个套接字编程服务器来同时处理多个客户端。但我无法正确实现它。我已经尝试了很长时间。我面临的问题是 1) 地址绑定问题 2) 如何处理父进程和子进程的问题 3) 如何结束服务器程序,即 ..返回控制台 我的单个客户端服务器程序运行正常。这里是我的多客户端-服务器代码。

#include<signal.h>
#include<stdio.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<sys/types.h>
#include<stdlib.h>

int main()
{

    struct sockaddr_in myaddr ,clientaddr;
    int sockid,newsockid;
    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(bind(sockid,( struct sockaddr*)&myaddr,len)==-1)
    {
        perror("bind");
    }
    if(listen(sockid,10)==-1)
    {
        perror("listen");
    }
    int pid,new;
    static int counter=0;
    for(;;)
    {       a:
            new =accept(sockid,(struct sockaddr *)&clientaddr,&len);

            if(pid=fork()==-1)
            {
                close(new);
                continue;

            }   
            else if(pid>0)
            {
            counter++;
            //wait();
            goto a;
            printf("here2");
            //close(new);
            continue;
            }   
            else if(pid==0)
            {
            counter++;
            printf("here 1");
            send(new,"hi",100,0);
            send(new,(char *) &counter,1,0);

            //kill(pid,SIGKILL);
            //close(new);
            }

    }
    printf("here3");
    close(sockid);
    return 0;
}

Here is the simple client program

这是简单的客户端程序

    #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;
}

Can someone please tell me what I am doing wrong and what is the correct way to do it..? Any help will be greatly appreciated...

有人可以告诉我我做错了什么,正确的做法是什么..?任何帮助将不胜感激...

回答by caf

The main problem you have is that ==has higher precedence than =, so this line:

您遇到的主要问题是==优先级高于=,所以这一行:

if(pid=fork()==-1)

is assigning the result of fork() == -1to pid, which isn't what you want: it'll always be 0when fork()succeeds, in both the child andthe parent. You need to use:

正在分配fork() == -1to的结果pid,这不是您想要的:在子级父级中成功0时总是如此。您需要使用:fork()

if((pid = fork()) == -1)

You should also close(new)in the parent after the fork()- the child owns that socket now. If you want to send the textual version of the counter, you need to use snprintf()to convert it to text. The child should also exit after it's finished - the easiest way to do that in your code is to break out of the loop. After these corrections, the inner loop in your server looks like:

您还应该close(new)在父级之后fork()- 子级现在拥有该套接字。如果要发送计数器的文本版本,则需要使用snprintf()将其转换为文本。孩子也应该在完成后退出 - 在您的代码中这样做的最简单方法是跳出循环。经过这些更正后,您服务器中的内部循环如下所示:

for(;;)
{
        new = accept(sockid, (struct sockaddr *)&clientaddr, &len);

        if ((pid = fork()) == -1)
        {
            close(new);
            continue;
        }
        else if(pid > 0)
        {
            close(new);
            counter++;
            printf("here2\n");
            continue;
        }
        else if(pid == 0)
        {
            char buf[100];

            counter++;
            printf("here 1\n");
            snprintf(buf, sizeof buf, "hi %d", counter);
            send(new, buf, strlen(buf), 0);
            close(new);
            break;
        }
}

回答by ravi bhuva

Try this one might you get solution,

试试这个你可能会得到解决方案,

Server Program:

服务器程序:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>

int main()
{
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;

server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(9734);
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address,server_len);

/* Create a connection queue, ignore child exit details and wait for
clients. */

listen(server_sockfd, 5);

signal(SIGCHLD, SIG_IGN);

while(1) {
char ch;

printf("server waiting\n");

/* Accept connection. */

client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, &client_len);

/* Fork to create a process for this client and perform a test to see
whether we're the parent or the child. */

if(fork() == 0) {

/* If we're the child, we can now read/write to the client on
client_sockfd.
The five second delay is just for this demonstration. */

read(client_sockfd, &ch, 1);
sleep(5);
ch++;
write(client_sockfd, &ch, 1);
close(client_sockfd);
exit(0);
}

/* Otherwise, we must be the parent and our work for this client is
finished. */

else {
close(client_sockfd);
}
}
}

Client Program:

客户端程序:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
void main()
{
    int sid;
    char s[10]={},s1[10]={};
    struct sockaddr_in ssock,csock;
    sid=socket(AF_INET,SOCK_STREAM,0);
    ssock.sin_family=AF_INET;
    ssock.sin_addr.s_addr=inet_addr("127.0.0.1");
    ssock.sin_port=htons(9734);
    connect(sid,(struct sockaddr *)&ssock,sizeof(ssock));
    while(1)
    {
        printf("\n Enter the string:");
        scanf("%s",s);
        write(sid,(void*)s,strlen(s));
        if(strlen(s)==0)
            break;
        sleep(1);
        read(sid,(void*)s1,sizeof(s1));
        printf("\n The received string is:%s\n",s1);
    }
    close(sid);
}

Here code is doing communication for only one character.

这里的代码只为一个字符进行通信。