TCP实现多用户聊天、通讯

创建服务端

功能:

1、实现10个用户的同时聊天,并且每两个用户之间都能聊天相互发送信息,并且具有群发消息的功能;

2、话语过滤功能:例如过滤信息中的fuck;

3、..............(另行添加)

实现:

1、在正常的TCP服务器的代码上进行改进,增加线程,以便实现多个用户的在线聊天;

2、函数模块:一个struct 用于收集中转用户的信息:套接字的文件描述符cfd  &  用户的IP及端口信息sockaddr

                       一个结构体用于分发、存储用户的信息:用户的名字name & 套接字的文件描述符cfd

                      线程函数:实现消息的接受,发送,打印用户信息

                      话语过滤函数

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

#define SERV_PORT 9527          /*服务端的端口号       */
#define ONLINEMAX 10             /*同时在线的最大人数   */

void *ChatOnline(void *arg);    /*线程的聊天,消息处理函数   */
void fuck_filter(const char* buf);
int UserSelect(char name);

/*用于用户信息的临时参数存储 ->  套接字的文件描述符 && IP+PORT  */
struct arg_user
{
        int cfd;
        struct sockaddr_in clit_addr;
};

/*用户信息的存放函数 ->用户名 && 套接字文件描述符    */
struct user
{
        char  name;
        int user_cfd;
}clit_user[ONLINEMAX];

/*报错函数  */
void sys_err(const char *str)
{
        perror(str);
        exit(1);
}

static int user_number = 0;     /* 用户的号数*/

int main()
{
        int sfd = 0,cfd = 0;
        int ret = 0,i = 0,tmp = 0;
        char buf[BUFSIZ];        //BUFSIZ大小为8192字节
        struct sockaddr_in serv_addr,clit_addr;
        struct arg_user *arg;
        socklen_t clit_addr_len;
        pthread_t pthread;

        /*设置 struct sockaddr_in 里面的内容 采用IPv4 端口号为9527 IP号由INADDR_ANY生成的二进制的IP地址   */
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(SERV_PORT);
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        /*生成套接字,并校验*/
        sfd = socket(AF_INET,SOCK_STREAM,0);
        if(sfd == -1){
                sys_err("socket error");
        }
        printf("socket .....");

        /*绑定端口号+IP地址  */
        bind(sfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
        printf("bind .......");

        /*设置监听的上限        */
        listen(sfd,20);
        printf("listen .....");

        int opt = SO_REUSEADDR;
        setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
      /*setsockopt()用来设置参数s所指定的socket状态。
      参数level代表欲设置的网络层,一般设成SOL_SOCKET以存取socket层。
      参数optname代表欲设置的选项,有下列几种数值:SO_REUSEADDR 允许在bind()过>程中本地地址可重复使用
        参数  optval代表欲设置的值,参数optlen则为optval的长度。
      返回值  成功则返回0,若有错误则返回-1,错误原因存于errno。*/
        /*监听,阻塞至有客户端连接,并返回一个新的套接字与客户端建立通讯 */

        clit_addr_len = sizeof(clit_addr);


        /*读取客户端发来的信息,并转化为大写    */
        while(1){
                printf("accept .....\n");
                cfd = accept(sfd,(struct sockaddr *)&clit_addr,&clit_addr_len);
                if(cfd == -1)   sys_err("accpet error");
//              printf("client's IP = %s",inet_ntoa(clit_addr.sin_addr));

/*指向结构体的结构体要先分配空间    将用户信息收集起来 */
                arg = malloc(sizeof(struct arg_user));
                arg->cfd = cfd;
                memcpy((void *)&arg->clit_addr, &clit_addr, sizeof(clit_addr));

                tmp = pthread_create(&pthread,NULL,ChatOnline,(void*)arg);
                if(tmp != 0)    sys_err("pthread_create faile");
        }

        close(sfd);
        close(cfd);
        return 0;
}

客户端的实现

/* client .c*/
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>

#define PORT 9527 
#define MAXDATASIZE 128

void* recv_proc(void* arg);
void* send_proc(void* arg);
int get_line(char *msg);


int main(int argc, char *argv[])
{
    int fd;
    pthread_t th1,th2;
    struct hostent *he;
    struct sockaddr_in server; //server's address info
    char *defaultIP = "127.0.0.1";
    //???
    if(argc != 2) {
        if((he = gethostbyname(defaultIP)) == NULL){
            perror("gethostbyname() error");
            exit(1);
        }
    }else{
       if((he = gethostbyname(argv[1])) == NULL){
            perror("gethostbyname() error");
            exit(1);
            }
    }

    if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("socket() error");
        exit(1);
    }

    bzero(&server , sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr = *((struct in_addr *)he->h_addr);

    if(connect(fd, (struct sockaddr *)&server,sizeof(struct sockaddr)) == -1){
        perror("connect() error");
        exit(1);
    }

    if(pthread_create(&th1, NULL, recv_proc, (void*)&fd)){
        perror("recv pthread_creat() error");
        close(fd);
        exit(1);
    }

    if(pthread_create(&th2, NULL, send_proc, (void*)&fd)){
        perror("send pthread_creat() error");
        close(fd);
        exit(1);
    }
    pthread_join(th1,NULL);
    pthread_join(th2,NULL);
    return 0;

}


void* recv_proc(void* arg)
{
    char recvline[MAXDATASIZE];
    int numbytes;
    int sockfd;

    printf("recv from server. \n");
    sockfd = *((int*)arg);
    while(1){
        if((numbytes = recv(sockfd, recvline, MAXDATASIZE, 0)) > 0){
            recvline[numbytes] = '\0';
            printf("\n[recvice:] %s\n", recvline);
            //clean output buffer
            memset(recvline, '0', strlen(recvline)-1);
        }else{
            //printf("recv error/null. ");          
        }
    }

}

void* send_proc(void* arg)
{
    char sendline[MAXDATASIZE];
    int numbytes;
    int len;
    int sockfd;

    printf("send to server. \n");
    sockfd = *((int*)arg);

    while(1)
    {
        //send message to server
        //when the string is not NULL , send another!
        while((len =get_line(sendline)) != 0){
            sendline[len] = '\0';
            send(sockfd, sendline, strlen(sendline), 0);
        }
    }

}

int get_line(char *msg)
{
    int i=0;
    char temp;

    printf("Input message:");
    fflush(stdout);
    while (1){
        temp = getchar();
        if (temp == '\r' || temp == '\n') {return i ;}
        msg[i]=temp;
        if(msg[i]==13){
                msg[i]=0;
                break;
        }
        fflush(stdout);
        i++;
    }
}

实现效果如下:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值