Linux下基于socket实现的简易多线程聊天室

设计思路

服务端

用一个数组来存放连接的客户端的sockid,一个COUNT来存放当前连接的客户端数量。服务端listen后一直处在accept状态,每接收到一个连接,就创建一个线程来完成与客户端的通信。当一个客户端发言时就遍历存放sockid的数组,向其它所有用户发送这条信息。

客户端

连接服务端后启动一个线程专门接收服务端返回的信息,主线程专门负责向服务端发送消息。

/*头文件*/

#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"
#include <signal.h>
#define PORT 8000
#define MAX 20

int sock_list[MAX], COUNT = 0;
pthread_mutex_t mutex_lock;

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

void delete(int sockid)
{
    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[100] = "login";
    char QUIT[100] = "quit";
    int res = 1;
    memset(name,0,sizeof(name));
    read(sockfd, name, sizeof(name));
    pthread_mutex_lock(&mutex_lock);
    sent(sockfd, name, LOGIN);
    pthread_mutex_unlock(&mutex_lock);
    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)
        { 
            pthread_mutex_lock(&mutex_lock);
            printf("client clsoe\n");
            sent(sockfd, name, QUIT);
            delete(sockfd);
            pthread_mutex_unlock(&mutex_lock);
            pthread_exit(0);
        }
        else
        {
            pthread_mutex_lock(&mutex_lock);
            printf("%s\n", buff);
            sent(sockfd, name, buff);
            pthread_mutex_unlock(&mutex_lock);
        }
    }
}


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;
    pthread_mutex_init(&mutex_lock,NULL);
    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;
}

猜你喜欢

转载自blog.csdn.net/Skuart/article/details/81115486