找到你要的答案

Q:Multithreaded client-server chat application in c language

Q:用C语言实现多线程客户机聊天应用

I wrote an application for communicating between two clients (one will run the server.c application, and the other one client.c). Everything goes very good at this point, both sides (client and server) can send and receive messages (there are two processes in both sides: one for listening and printing messages, and one for receiving and sending back messages).

There is what I got so far:

client.c

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

#include "aes.h"

#define BSIZE 320

uint8_t key[] = "qwertyuioplkjhg";
uint8_t iv[]  = "123456789098765";

void error(const char *msg) {
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[]) {
    int sockfd, portno, n, pid;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[BSIZE];
    char paddedData[BSIZE];
    unsigned char crypted_data[BSIZE];

    if (argc < 3) {
        fprintf(stderr,"usage %s <hostname> <port>\n", argv[0]);
        exit(0);
    }

    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0) {
        error("ERROR opening socket");
    }

    server = gethostbyname(argv[1]);

    if (server == NULL) {
        fprintf(stderr, "ERROR, no such host\n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portno);

    if(connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) {
        error("ERROR connecting");
    }

    //while(1) {
    switch(pid = fork()) {
    case -1:
        error("ERROR fork");
    case 0:
        while(1) {
            //printf("Please enter the message: ");
            bzero(buffer, BSIZE);
            //printf("Message: ");
            fgets(buffer, BSIZE - 1, stdin);

            strncpy(paddedData, buffer, BSIZE);
            AES128_CBC_encrypt_buffer(crypted_data, (unsigned char*)paddedData, BSIZE, key, iv);

            n = write(sockfd, crypted_data, BSIZE - 1);

            if(n < 0) {
                error("ERROR writing to socket");
            }
        }
    default:
        while(1) {
            //bzero(buffer,256);

            n = read(sockfd, buffer, BSIZE - 1);

            AES128_CBC_decrypt_buffer((unsigned char*)paddedData, (unsigned char*)buffer, BSIZE, key, iv);

            if(n < 0) {
                error("ERROR reading from socket");
            }

            printf("<<server>>: %s", paddedData);
        }
    }

    close(sockfd);

    return 0;
}

and server.c

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

#include "aes.h"
#define BSIZE 320

uint8_t key[] = "qwertyuioplkjhg";
uint8_t iv[]  = "123456789098765";

int numberOfConnections = 0;

void communications_handler(int);

void error(const char *msg) {
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[]) {
    int sockfd, newsockfd, portno, pid;
    socklen_t clilen;
    struct sockaddr_in serv_addr, cli_addr;

    if(argc < 2) {
        fprintf(stderr, "ERROR, no port provided\n");
        exit(1);
    }

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if(sockfd < 0) {
        error("ERROR opening socket");
    }

    bzero((char*)&serv_addr, sizeof(serv_addr));

    portno = atoi(argv[1]);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    if(bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
        error("ERROR on binding");
    }

    listen(sockfd, 5);
    clilen = sizeof(cli_addr);

    while(1) {
        /* [1] */
        newsockfd = accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
        numberOfConnections++;
        printf("\nThere are %d clients connected!\n\n", numberOfConnections);

        if (newsockfd < 0) {
            error("ERROR on accept");
        }

        pid = fork();

        if (pid < 0) {
            error("ERROR on fork");
        }

        if (pid == 0) {
            close(sockfd);
            communications_handler(newsockfd);
            exit(0);
        }

        else {
            close(newsockfd);
        }
    }

    close(sockfd);

    return 0;
}

void communications_handler(int sock) {
    int n, pid;
    char buffer[BSIZE];
    char paddedData[BSIZE];
    unsigned char crypted_data[BSIZE];

    switch(pid = fork()) {
    case -1:
        error("ERROR on fork");
    case 0:
        while(1) {
            n = read(sock, buffer, BSIZE - 1);

            AES128_CBC_decrypt_buffer((unsigned char*)paddedData, (unsigned char*)buffer, BSIZE, key, iv);

            if(n < 0) {
                error("ERROR reading from socket");
            }

            printf("<<client>>: %s", paddedData);
        }
    default:
        while(1) {
            bzero(buffer, BSIZE);
            //printf("Message: ");
            fgets(buffer, BSIZE - 1, stdin);

            strncpy(paddedData, buffer, BSIZE);
            AES128_CBC_encrypt_buffer(crypted_data, (unsigned char*)paddedData, BSIZE, key, iv);

            for(int i = 0; i < numberOfConnections; i++) {
                n = write(sock, crypted_data, BSIZE - 1);
            }

            if(n < 0) {
                error("ERROR writing to socket");
            }
        }
    }
}

Now I want to extend this program, by letting the server to accept multiple connections (I actually did this, in server.c, at [1]).

But there is now one problem: How can I implement the communication between two (or more) clients (the server will only accept new connections, read data from all connected clients, and send data back to all clients).

Can this be done with processes?

I wrote an application for communicating between two clients (one will run the server.c application, and the other one C客户。). Everything goes very good at this point, both sides (client and server) can send and receive messages (there are two processes in both sides: one for listening and printing messages, and one for receiving and sending back messages).

有什么我到目前为止:

C客户。

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

#include "aes.h"

#define BSIZE 320

uint8_t key[] = "qwertyuioplkjhg";
uint8_t iv[]  = "123456789098765";

void error(const char *msg) {
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[]) {
    int sockfd, portno, n, pid;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[BSIZE];
    char paddedData[BSIZE];
    unsigned char crypted_data[BSIZE];

    if (argc < 3) {
        fprintf(stderr,"usage %s <hostname> <port>\n", argv[0]);
        exit(0);
    }

    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0) {
        error("ERROR opening socket");
    }

    server = gethostbyname(argv[1]);

    if (server == NULL) {
        fprintf(stderr, "ERROR, no such host\n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portno);

    if(connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) {
        error("ERROR connecting");
    }

    //while(1) {
    switch(pid = fork()) {
    case -1:
        error("ERROR fork");
    case 0:
        while(1) {
            //printf("Please enter the message: ");
            bzero(buffer, BSIZE);
            //printf("Message: ");
            fgets(buffer, BSIZE - 1, stdin);

            strncpy(paddedData, buffer, BSIZE);
            AES128_CBC_encrypt_buffer(crypted_data, (unsigned char*)paddedData, BSIZE, key, iv);

            n = write(sockfd, crypted_data, BSIZE - 1);

            if(n < 0) {
                error("ERROR writing to socket");
            }
        }
    default:
        while(1) {
            //bzero(buffer,256);

            n = read(sockfd, buffer, BSIZE - 1);

            AES128_CBC_decrypt_buffer((unsigned char*)paddedData, (unsigned char*)buffer, BSIZE, key, iv);

            if(n < 0) {
                error("ERROR reading from socket");
            }

            printf("<<server>>: %s", paddedData);
        }
    }

    close(sockfd);

    return 0;
}

和服务器。

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

#include "aes.h"
#define BSIZE 320

uint8_t key[] = "qwertyuioplkjhg";
uint8_t iv[]  = "123456789098765";

int numberOfConnections = 0;

void communications_handler(int);

void error(const char *msg) {
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[]) {
    int sockfd, newsockfd, portno, pid;
    socklen_t clilen;
    struct sockaddr_in serv_addr, cli_addr;

    if(argc < 2) {
        fprintf(stderr, "ERROR, no port provided\n");
        exit(1);
    }

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if(sockfd < 0) {
        error("ERROR opening socket");
    }

    bzero((char*)&serv_addr, sizeof(serv_addr));

    portno = atoi(argv[1]);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    if(bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
        error("ERROR on binding");
    }

    listen(sockfd, 5);
    clilen = sizeof(cli_addr);

    while(1) {
        /* [1] */
        newsockfd = accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
        numberOfConnections++;
        printf("\nThere are %d clients connected!\n\n", numberOfConnections);

        if (newsockfd < 0) {
            error("ERROR on accept");
        }

        pid = fork();

        if (pid < 0) {
            error("ERROR on fork");
        }

        if (pid == 0) {
            close(sockfd);
            communications_handler(newsockfd);
            exit(0);
        }

        else {
            close(newsockfd);
        }
    }

    close(sockfd);

    return 0;
}

void communications_handler(int sock) {
    int n, pid;
    char buffer[BSIZE];
    char paddedData[BSIZE];
    unsigned char crypted_data[BSIZE];

    switch(pid = fork()) {
    case -1:
        error("ERROR on fork");
    case 0:
        while(1) {
            n = read(sock, buffer, BSIZE - 1);

            AES128_CBC_decrypt_buffer((unsigned char*)paddedData, (unsigned char*)buffer, BSIZE, key, iv);

            if(n < 0) {
                error("ERROR reading from socket");
            }

            printf("<<client>>: %s", paddedData);
        }
    default:
        while(1) {
            bzero(buffer, BSIZE);
            //printf("Message: ");
            fgets(buffer, BSIZE - 1, stdin);

            strncpy(paddedData, buffer, BSIZE);
            AES128_CBC_encrypt_buffer(crypted_data, (unsigned char*)paddedData, BSIZE, key, iv);

            for(int i = 0; i < numberOfConnections; i++) {
                n = write(sock, crypted_data, BSIZE - 1);
            }

            if(n < 0) {
                error("ERROR writing to socket");
            }
        }
    }
}

现在我想扩展这个程序,通过让服务器接受多个连接(实际上我在服务器C中做了这个,在[ 1 ])。

但现在有一个问题:如何实现两个(或更多)客户之间的通信(服务器只接受新的连接,从所有连接的客户端读取数据,并将数据发送回所有客户端)。

这可以用流程来完成吗?

answer1: 回答1:

Have a look at Beej's guide to non-blocking socket programming: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#select

在Beej的非阻塞套接字编程指南一看:HTTP:/ / Beej。我们/指导/ bgnet /输出/ HTML /分页/ bgnet HTML #选择。

c  linux  multithreading  sockets  fork