Simple multithreaded chat room based on socket under Linux

Design thinking

Server side

An array is used to store the sockid of connected clients, and a COUNT is used to store the number of currently connected clients. After the server listens, it is always in the accept state. Every time it receives a connection, it creates a thread to complete the communication with the client. When a client speaks, it will traverse the array of sockids and send this information to all other users.

Client

After connecting to the server, start a thread to receive the information returned by the server. The main thread is responsible for sending messages to the server.

/*Header file*/

#ifndef _PUBLIC_H
#define _PUBLIC_H

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

#endif
/*server.c*/
#include "public.h"
#define PORT 8000
#define MAX 20

int sock_list[MAX], COUNT = 0; //Global variable storagesockid


void sent(const int sockid,const char *name, const char *str)       //Send messages to connected clients
{
    printf("sending..\n");
    for (int i = 0; i < COUNT; i++)
    {
        /* code */
        if(sock_list[i] != sockid)
        {
            write(sock_list[i], name, sizeof(name));
            sleep(1);
            write(sock_list[i], str, sizeof(str));
        }
    }
}

void delete(int sockid)     //Remove a client from the array after exiting
{
    for (int i = 0; i < COUNT; i++)
    {
        if(sock_list[i] == sockid)
        {
            close(sockid);
            for (int j = i; i < COUNT - 1; j++)
            {
                sock_list[j] = sock_list[j+1];
            }
            COUNT--;
            break;
        }
    }
}

void *pth_rec(void *cli_sockfd) 
{
    int sockfd = *((int *)cli_sockfd);
    char buff[100];
    char name[20];
    char *LOGIN = "login";
    char *QUIT = "quit";
    int res = 1;
    memset(name,0,sizeof(name));
    read(sockfd, name, sizeof(name));
    sent(sockfd, name, LOGIN);
    while(res)
    {
        memset(buff,0,sizeof(buff));
        res = read(sockfd, buff, sizeof(buff));
        if(res < 0)
        {
            perror("read failed");
            exit(-1);
        }
        else if (res == 0)
        { 
            printf("client clsoe\n");
            sent(sockfd, name, QUIT);
            delete(sockfd);
            pthread_exit(0);
        }
        else
        {
            printf("%s\n", buff);
            sent(sockfd, name, buff);
        }
    }
}


int main()
{
    int sockfd;
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket failed");
        exit(-1);
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    inet_aton("127.0.0.1", &addr.sin_addr);
    int on=1;
    if((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0)
    {
        perror("setsockopt failed");
        exit(-1);
    }
    if(bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
    {
        perror("bind failed");
        exit(-1);
    }
    if(listen(sockfd, MAX) == -1)
    {
        perror("listen failed");
        exit(-1);
    }
    printf("listen..\n");

    pthread_t tid;
    int cli_sockfd, ret;
    struct sockaddr_in cli_addr;
    socklen_t len = sizeof(cli_addr);
    while(1)
    {
        cli_sockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &len);
        if(cli_sockfd == -1)
        {
            perror("accept failed");
            exit(-1);
        }
        printf("%s  connect\n", inet_ntoa(cli_addr.sin_addr));
        sock_list[COUNT++] = cli_sockfd;
        ret = pthread_create(&tid, NULL, pth_rec, &cli_sockfd);
        if(ret != 0)
        {
            perror("pthread failed");
            exit(-1);
        }
    }
    return 0;
}
/*client.c*/
#include "public.h"

#define PORT 8000

int sockfd;

void * pth_rec()
{
    char name[20];
    char buff[100];
    while(1)
    {
        memset(name, 0, sizeof(name));
        memset(buff, 0, sizeof(buff));
        read(sockfd, name, sizeof(name));
        //printf("%s\n", name);
        read(sockfd, buff, sizeof(buff));
        printf("%s:%s\n", name, buff);
    }
}

int main()
{
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1)
    {
        perror("socket failed");
        exit(-1);
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    inet_aton("127.0.0.1", &addr.sin_addr);
    if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
    {
        perror("connect failed");
        exit(-1);
    }
    printf("connect success\n");
    pthread_t t_id;
    char name[20];
    printf("Input your name\n");
    scanf("%s", name);
    getchar();
    if(write(sockfd, name, strlen(name)) < 0)
    {
        perror("read failed");
        exit(-1);
    }

    pthread_create(&t_id, NULL, pth_rec, NULL);
    while(1)
    {
        char buff[100];
        scanf("%s", buff);
        if(strcmp(buff, "quit") == 0)
        {
            break;
        }
        if(write(sockfd, buff, strlen(buff)) < 0)
        {
            perror("read failed");
            exit(-1);
        }

    }
    close(sockfd);

    return 0;
}

Tags: socket

Posted on Sun, 09 Feb 2020 10:45:21 -0800 by Patty