多个客户端通过套接字连接

时间:2013-12-10 18:41:08

标签: sockets concurrency

我是套接字编程的新手。我试图将服务器连接到多个客户端,我有两个问题。 1)除非我得到回复,否则我无法发送消息,即如果客户端连接并发送消息,则客户端无法再次发送消息,直到它从服务器获得回复。如果客户端键入一些消息,它会存储消息,并在收到消息后发送消息。 2)我想将连接数限制为1,如果某个连接没有其他人应该连接,直到客户端退出客户端。如果客户退出,那么第一个等待的人应该连接。

服务器

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<errno.h>
    #include<string.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include <arpa/inet.h>
    #include <sys/wait.h>
    #include <signal.h>
    #define MYPORT 3490 /* the port users connect to */
    #define BACKLOG 0 /* max no. of pending connections in server queue */
    #define MAXDATASIZE 200
    void sigchld_handler(int s) 
{
while( wait( NULL) > 0); /* wait for any child to finish */
}
    int main( void) 
{
int listenfd;
/* listening socket */
int connfd;
/* connection socket */
struct sockaddr_in server_addr; /* info for my addr i.e. server */
struct sockaddr_in client_addr; /* client's address info */
int sin_size;
/* size of address structure */
struct sigaction sa; /* deal with signals from dying children! */
int yes = 1;
char clientAddr[ 20]; /* holds ascii dotted quad address */
if ((listenfd = socket( AF_INET, SOCK_STREAM, 0)) == -1) 
    {
    perror( "Server socket");
    exit( 1);
    }
/* Set Unix socket level to allow address reuse */
if( setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR,&yes, sizeof( int)) == -1) 
    {
    perror( "Server setsockopt");
    exit( 1);
    }   
sin_size = sizeof( server_addr);
memset( &server_addr, 0, sin_size);
/* zero struct */
server_addr.sin_family = AF_INET;
/* host byte order ... */
server_addr.sin_port = htons( MYPORT); /* . short, network byte order */
server_addr.sin_addr.s_addr = INADDR_ANY; /* any server IP addr */
if( bind( listenfd, (struct sockaddr *)&server_addr,sizeof( struct sockaddr)) == -1) 
    {
    perror( "Server bind");
    exit( 1);
    }
if( listen( listenfd, BACKLOG) == -1) 
    {
    perror( "Server listen");
    exit( 1);
    }
/* Signal handler stuff */
sa.sa_handler = sigchld_handler; /* reap all dead processes */
sigemptyset( &sa.sa_mask);
sa.sa_flags = SA_RESTART;
if( sigaction( SIGCHLD, &sa, NULL) == -1) 
    {
    perror( "Server sigaction");
    exit( 1);
    }
while( 1) 
    {
    /* main accept() loop */
    sin_size = sizeof( struct sockaddr_in);
    if( (connfd = accept( listenfd,(struct sockaddr *)&client_addr, &sin_size)) == -1) 
        {
        perror( "Server accept");
        continue;
        }
    strcpy( clientAddr, inet_ntoa( client_addr.sin_addr));
    printf( "Server: got connection from %s\n", clientAddr);
    if( !fork()) 
        {
        /* the child process dealing with a client */
        char msg[ MAXDATASIZE];
        int numbytes;
        close( listenfd); /* child does not need the listener */
        msg[ 0] = '\0';
        /* no message yet! */
    do 
        {
        if( (numbytes =recv( connfd, msg, MAXDATASIZE -1, 0)) == -1) 
            {
            perror( "Server recv");
            exit( 1);
            /* error end of child */
            }
    msg[ numbytes] = '\0';
    /* end of string */
    fprintf( stderr, "Message received: %s\n", msg);
    do 
        {
        if( strcmp( msg, "quit") == 0)
                        {
                        close( connfd);
                        exit(0);
                        }
        printf( "Message to send: ");
        scanf( "%s", msg);
        if( send( connfd, msg, strlen( msg), 0) == -1) 
            {
            perror( "server send");
            //exit(1);
            }
        /* error end of child */
        }
    while( strcmp( msg, "quit") != 0);
    if( strcmp( msg, "quit") == 0)
        {
        close( connfd);
        exit(0);
        }
    //close( connfd);
    //exit(0);
/* end of child! */
    }
while(1); 
//fork(); 
//close(connfd); /* parent does not need the connection socket */
return 0;
}
}
}

客户端:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h> 
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    /* for gethostbyname() */
    #define PORT 3490
    /* server port the client connects to */
    #define MAXDATASIZE 100 /* max bytes to be received at once */</i>
    int main( int argc, char * argv[]) 
    {
    int sockfd, numbytes;
    char buf[ MAXDATASIZE];
    struct hostent *he;
    struct sockaddr_in their_addr; /* server address info */
    char msg[ MAXDATASIZE];
    if( argc != 2) {
    fprintf( stderr, "usage: client hostname\n");
    exit( 1);
    }
    /* resolve server host name or IP address */
    if( (he = gethostbyname( argv[ 1])) == NULL) { /* host server info */
    perror( "Client gethostbyname");
    exit( 1);
    }
    if( (sockfd = socket( AF_INET, SOCK_STREAM, 0)) == -1) { 
    perror( "Client socket");
    exit( 1);
    }
    memset( &their_addr, 0, sizeof( their_addr));
    /* zero all */
    their_addr.sin_family = AF_INET;
    /* host byte order .. */
    their_addr.sin_port = htons( PORT);
    /* .. short, network byte order */
    their_addr.sin_addr = *((struct in_addr *)he -> h_addr);
    if( connect( sockfd, (struct sockaddr *)&their_addr,
    sizeof( struct sockaddr)) == -1) {
    perror( "Client connect");
    exit( 1);
    }
    do {
    printf( "Message to send: ");
    scanf( "%s", msg);
    if( (numbytes = send( sockfd, msg, strlen( msg), 0)) == -1) {
    perror( "Client send");
    continue;
    } 
    if( (numbytes = recv( sockfd, buf, MAXDATASIZE - 1, 0)) == -1) {
    perror( "Client recv");
    continue;
    }
    buf[ numbytes] = '\0';
    /* end of string char */
    printf( "Received: %s\n", buf);
    } while( strcmp( msg, "quit") != 0);
    close( sockfd);
    return 0;
    }

2 个答案:

答案 0 :(得分:0)

亲爱的,您必须使用多线程来启动新线程来处理新连接

该线程中的

也使用单独的线程来接收数据和发送数据......

答案 1 :(得分:0)

  

1)除非得到回复,否则我无法发送消息,即如果客户端连接   并发送消息,客户端无法再次发送消息,直到它获得   来自服务器的回复。

毫无疑问,因为您已在客户端的scanf循环中编写了recvdo的顺序排列。要按照出现的顺序处理消息输入和套接字接收,我们可以使用select;您的do循环可能如下所示:

    do
    {   fd_set fds;
        FD_ZERO(&fds);
        FD_SET(STDIN_FILENO, &fds);
        FD_SET(sockfd, &fds);   // set of descriptors holds stdin and socket
        printf("Message to send: "), fflush(stdout);
        if (select(sockfd+1, &fds, NULL, NULL, NULL) < 0) break;    // error?
        // see which descriptors of set are ready
        if (FD_ISSET(STDIN_FILENO, &fds))
        {   // it is the standard input
            scanf("%s", msg);
            numbytes = send(sockfd, msg, strlen(msg), 0);
            if (numbytes == -1) perror("Client send");
        }
        if (FD_ISSET(sockfd, &fds))
        {   // this is the peer's message or termination
            numbytes = recv(sockfd, buf, MAXDATASIZE - 1, 0);
            if (numbytes <= 0)
            {
                perror("Client recv");
                break;  // no more data from peer, so close the connection
            }
            buf[numbytes] = '\0';   /* end of string char */
            printf("Received: %s\n", buf);
        }
    } while (strcmp(msg, "quit") != 0);
  

2)我想将连接数限制为1,如果是的话   连接没有其他人应该连接,直到客户端退出客户端。

我们可以通过在我们accept客户端连接请求之后分配服务器进程来实现这一点,而是在唯一的服务器任务本身中处理消息传输(非常相似)如上所示为客户);只需忽略行if( !fork())以及return 0;而取消注释close(connfd);,并在break时忘记do循环recv }返回一个非正值。