【问题标题】:Multithreaded client-server chat application in c languagec语言中的多线程客户端-服务器聊天应用程序
【发布时间】:2015-07-12 02:05:08
【问题描述】:

我编写了一个应用程序用于在两个客户端之间进行通信(一个将运行 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] 中这样做的)。

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

这可以通过进程来完成吗?

【问题讨论】:

  • 您是否查看过任何教程,因为如果您稍微搜索一下,确实有 数千个 的教程和服务器接受和处理多个连接的示例。其中许多只是聊天服务器和客户端。

标签: c linux multithreading sockets fork


【解决方案1】:

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

【讨论】:

  • 您的答案仅包含一个链接,如果链接被破坏,将完全没有价值。总结重要信息,即使链接不存在,您的帖子也能回答问题。然后,您仍可以保留答案中的链接作为参考和更多信息。
  • 答案链接已失效,请改用this
猜你喜欢
  • 2014-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-17
  • 2013-04-09
  • 2011-06-18
  • 1970-01-01
相关资源
最近更新 更多