22
Май
2017

Многопользовательский чат на базе Sockets на C с использованием POSIX Threads

Написал пару client-server. Пока, что клиенты могут отправлять сообщения на сервер, где они и отображаются.

Необходимо, чтобы после получения сообщения от клиента, сервер отправлял его всем, кроме отправившего(ну или включая его).

Хотелось бы реализовать это с помощью mutex'ов, но я пока что слабо представляю как. Буду благодарен за помощь.

server.cpp:

// Default is the port 1234.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>

int Flag=0;

void* NewCon(void* arg);
static void usage();

int main(int argc, char *argv[]) //
{
    if (argc > 1 && *(argv[1]) == '-') 
    {
        usage(); exit(1);
    }
    int ListenPort = 1234;
    if (argc > 1)
        ListenPort = atoi(argv[1]);
    // Create a socket
    int Socket0 = socket(AF_INET, SOCK_STREAM, 0);
    if (Socket0 < 0) 
    {
        perror("Cannot create a socket"); 
        exit(1);
    }

    // Fill in the address structure containing self address
    struct sockaddr_in MyAddr;
    memset(&MyAddr, 0, sizeof(struct sockaddr_in));
    MyAddr.sin_family = AF_INET;
    MyAddr.sin_port = htons(ListenPort);        // Port to listen
    MyAddr.sin_addr.s_addr = htonl(INADDR_ANY); 

    // Bind a socket to the address
    int Result = bind(Socket0, (struct sockaddr*) &MyAddr, sizeof(MyAddr));
    if (Result < 0) 
    {
        perror("Cannot bind a socket"); exit(1);
    }
    // Set the "LINGER" timeout to zero, to close the listen socket
    // immediately at program termination.
    struct linger LingerOpt = { 1, 0 }; // Linger active, timeout 0
    setsockopt(Socket0, SOL_SOCKET, SO_LINGER, &LingerOpt, sizeof(LingerOpt));

    // Now, listen for a connection
    Result = listen(Socket0, 100);    // "100" is the maximal length of the queue
    if (Result < 0) 
    {
        perror("Cannot listen"); exit(1);
    }

    pthread_t ThreadM[100];
    int i(0), Mastr;
    while(i<100)
    {
        if(Flag<1)
        {
            Mastr = pthread_create(&(ThreadM[i]), NULL, &NewCon, &Socket0);
            if (Mastr != 0) 
            {
                printf("Cannot create thread %d",i+1); exit(1);
            }
            printf("Thread %d is created.\n",i+1);
            i++;
            Flag++; 
        }
    }
    while(i>-1)
    {
        pthread_join(ThreadM[i], NULL);
        i--;
    }
    Result = close(Socket0);    // Close the listen socket
    return 0;
}

void* NewCon(void* Argument)
{
    //pthread_mutex_lock(&mutex);
    int Socket0 = *((int *) Argument);
    int Result;
    struct sockaddr_in PeerAddr;
    socklen_t PeerAddrLen = sizeof(PeerAddr);
    int Socket1 = accept(Socket0, (struct sockaddr*) &PeerAddr, &PeerAddrLen);
    //pthread_mutex_unlock(&mutex);
    Flag--;
    if (Socket1 < 0) {
        perror("Cannot accept"); 
        exit(1);
    }
    // A connection is accepted. The new socket "s1" is created
    // for data input/output. The peeraddr structure is filled in with
    // the address of connected entity, print it.
    printf(
        "Connection from IP %d.%d.%d.%d, port %d\n",
        (ntohl(PeerAddr.sin_addr.s_addr) >> 24) & 0xff, // High byte of address
        (ntohl(PeerAddr.sin_addr.s_addr) >> 16) & 0xff, // . . .
        (ntohl(PeerAddr.sin_addr.s_addr) >> 8) & 0xff,  // . . .
        ntohl(PeerAddr.sin_addr.s_addr) & 0xff,         // Low byte of addr
        ntohs(PeerAddr.sin_port)
    );
    write(Socket1, "Hello!\n", 8);

    char Buffer[1024]; 
    int i(1);
    while(i>0)
    {
        Result = read(Socket1, Buffer, 1023);
        if (Result < 0) {
            perror("Read error"); exit(1);
        }
        if((Buffer[0]=='e')&&(Buffer[1]=='x')&&(Result==4))
        {
            //printf("lol\n");
            i=-1;
        }
        Buffer[Result] = 0;
        printf("Received %d bytes:\n%s", Result, Buffer);
    }
    write(Socket1, "Disconnect\r\n", 12);
    close(Socket1);  // Close the data socket
    return NULL;
}

static void usage() {
    printf(
        "Usage:\n"
        "     server [port_to_listen]\n"
        "Default is the port 1234.\n"
    );
}

client.cpp:

//          client [IP_address_of_server [port_of_server]]
//      where IP_address_of_server is either IP number of server
//      or a symbolic Internet name, default is "localhost"; port_of_server is a port number, default is 1234.

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

static void usage();

int main(int argc, char *argv[]) 
{
    if (argc > 1 && *(argv[1]) == '-') 
    {
        usage();
        exit(1);
    }
    // Create a socket
    int Socket0 = socket(AF_INET, SOCK_STREAM, 0);
    if (Socket0 < 0) 
    {
        perror("Cannot create a socket"); exit(1);
    }

    // Fill in the address of server
    struct sockaddr_in PeerAddr;
    memset(&PeerAddr, 0, sizeof(PeerAddr));
    const char* PeerHost = "localhost";
    if (argc > 1)
        PeerHost = argv[1];

    // Resolve the server address (convert from symbolic name to IP number)
    struct hostent *Host = gethostbyname(PeerHost);
    if (Host == NULL) 
    {
        perror("Cannot define host address"); exit(1);
    }
    PeerAddr.sin_family = AF_INET;
    short PeerPort = 1234;
    if (argc >= 3)
        PeerPort = (short) atoi(argv[2]);
    PeerAddr.sin_port = htons(PeerPort);

    // Print a resolved address of server (the first IP of the host)
    printf(
        "peer addr = %d.%d.%d.%d, port %d\n",
        Host->h_addr_list[0][0] & 0xff,
        Host->h_addr_list[0][1] & 0xff,
        Host->h_addr_list[0][2] & 0xff,
        Host->h_addr_list[0][3] & 0xff,
        (int) PeerPort
    );

    // Write resolved IP address of a server to the address structure
    memmove(&(PeerAddr.sin_addr.s_addr), Host->h_addr_list[0], 4);

    // Connect to a remote server
    int Result = connect(Socket0, (struct sockaddr*) &PeerAddr, sizeof(PeerAddr));
    if (Result < 0) 
    {
        perror("Cannot connect"); 
        exit(1);
    }
    printf("Connected. Reading a server message.\n");

    char Buffer[1024];
    Result = read(Socket0, Buffer, 1024);
    if (Result < 0) 
    {
        perror("Read error");
        exit(1);
    }
    printf("Received:\n%s", Buffer);

    int i(1);
    char c = 'q';
    int j(0);
    while(i>0)
    {

        while(c != '\n'&&j<1020)   
        {
            c = getchar();
            Buffer[j] = c;
            ++j;
        }
        c = 'q';
        Buffer[j-1] = '\r'; //возврат каретки в начало строки
        Buffer[j] = '\n';
        if((Buffer[0]=='e')&&(Buffer[1]=='x')&&(j==3))
        {
            printf("\n");
            i=-1;
        }
        write(Socket0, Buffer, j+1);
        j=0;
    }
    Result = read(Socket0, Buffer, 1023);
    Buffer[Result] = 0;
    printf("Received:\n%s", Buffer);
    close(Socket0);
    return 0;
}

static void usage() {
    printf(
        "Chat.\n"
        "Usage:\n"
        "         client [IP_addResults_of_server [port_of_server]]\n"
        "     where IP_address_of_server is either IP number of server\n"
        "     or a symbolic Internet name, default is \"localhost\";\n"
        "     port_of_server is a port number, default is 1234.\n"
        "The client connects to a server which address is given in a\n"
        "command line, receives a message from a server, sends the message\n"
    );
}

Источник: https://ru.stackoverflow.com/questions/669446/%D0%9C%D0%BD%D0%BE%D0%B3%D0%BE%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%B8%D0%B9-%D1%87%D0%B0%D1%82-%D0%BD%D0%B0-%D0%B1%D0%B0%D0%B7%D0%B5-sockets-%D0%BD%D0%B0-c-%D1%81-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC-posix-threads

Share

Тебе может это понравится...