C:“所有客户端连接的相同文件描述符”(客户端服务器编程)

时间:2011-05-06 17:51:57

标签: c sockets client-server

在每个新客户端连接分叉服务器进程

不同的进程(服务器的其他子进程,即exec)无法识别在分叉子进程中使用相同fd的客户端。

如何区分其他进程的客户端?

如果文件描述符为new sockfd

,则accept调用返回相同的值
/* server process */ 
#include <ctype.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <signal.h> 
#define SIZE sizeof(struct sockaddr_in) 
void catcher(int sig); 
int newsockfd; 
int main(void) 
{ 
    int sockfd; 
    char c;
    struct sockaddr_in server = {AF_INET, 7000, INADDR_ANY}; 
    static struct sigaction act; 
    act.sa_handler = catcher; 
    sigfillset(&(act.sa_mask)); 
    sigaction(SIGPIPE, &act, NULL); 
    /* set up the transport end point */ 
    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    { 
        perror("socket call failed"); 
        exit(1); 
    } 
    /* bind an address to the end point */ 
    if ( bind(sockfd, (struct sockaddr *)&server, SIZE) == -1) 
    { 
        perror("bind call failed"); 
        exit(1); 
    }
    /* start listening for incoming connections */ 
    if ( listen(sockfd, 5) == -1 ) 
    { 
        perror("listen call failed"); 
        exit(1) ; 
    } 
    for (;;) 
    { 
        /* accept a connection */ 
        if ( (newsockfd = accept(sockfd, NULL, NULL)) == -1) 
        { 
            perror("accept call failed"); 
            continue; 
        } 
        printf("New connection. File descriptor fd is %d\n",newsockfd);
        /* spawn a child to deal with the connection */
        if ( fork() == 0) 
        { 
            while (recv(newsockfd, &c, 1, 0) > 0) 
            { 
                c = toupper(c); 
                send(newsockfd, &c,1, 0); 
            } 
            /* when client is no longer sending information the socket can be closed and the child process terminated */ 
            close(newsockfd); 
            exit (0); 
        } 
        /* parent doesn't need the newsockfd */ 
        close(newsockfd); 
    } 
} 
void catcher(int sig) 
{ 
    close(newsockfd); 
    exit (0); 
}












/* client process */ 
#include <ctype.h> 
#include <sys/types.h> 
#include<stdlib.h>
#include<stdio.h>
#include <sys/socket.h> 
#include <netinet/in.h> 
#define SIZE sizeof(struct sockaddr_in) 
int main(void) 
{ 
    int sockfd; 
    char c, rc; 
    struct sockaddr_in server = {AF_INET, 7000}; 
    /* convert and store the server's IP address */ 
    server.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    /* set up the transport end point */ 
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    { 
        perror("socket call failed"); 
        exit(1); 
    } 
    /* connect the socket to the server's address */ 
    if ( connect (sockfd, (struct sockaddr *)&server, SIZE) == -1) 
    { 
        perror("connect call failed"); 
        exit(1); 
    } 
    /* send and receive information with the server */ 
    for(rc = '\n';;) 
    { 
        if (rc == '\n') 
            printf("Input a lower case character\n"); 
        c = getchar(); 
        send(sockfd, &c, 1, 0); 
        if (recv(sockfd, &rc, 1, 0) >0) 
            printf("%c", rc);  
        else 
        {
            printf("server has died\n");
            close(sockfd);
            exit(1); 
        } 
    } 
} 

1 个答案:

答案 0 :(得分:3)

文件描述符号仅在其存在的过程中是唯一的,并且一旦关闭,它就可以被重用(例如,下次调用accept时)。它不是“连接标识符”的好选择。

在您为每个连接创建新进程的情况下,连接的最自然标识符将是进程ID - 但是您通过不保存fork的返回值将其抛弃。在父进程中,fork返回它创建的子进程的pid。您想要保存它并在以后使用它。特别是,您可以使用它来终止子进程或确定子进程何时退出(wait - 系列函数将告诉您退出哪个子进程。)

当然,如果你的整个模型是为每个连接使用一个单独的进程,我不确定为什么你需要在父进程中识别连接。如果每个连接都不是一个完全独立的进程,那么使用线程而不是进程可能会做得更好。