c语言的多线程客户端 - 服务器聊天应用程序

时间:2015-05-02 09:07:11

标签: c linux multithreading sockets fork

我写了一个用于两个客户端之间通信的应用程序(一个将运行server.c应用程序,另一个运行client.c)。 此时一切都很顺利,双方(客户端和服务器)都可以发送和接收消息(双方都有两个进程:一个用于监听和打印消息,一个用于接收和发送消息)。

到目前为止我得到的是:

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

和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");
            }
        }
    }
}

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

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

这可以通过流程完成吗?

1 个答案:

答案 0 :(得分:0)

查看Beej的非阻塞套接字编程指南:http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#select