• Linux 系统下的简单聊天室(C语言实现)


    server:
    #include<stdlib.h>
    #include<stdio.h>
    #include<string.h>
    #include<errno.h>
    #include<netdb.h>
    #include<sys/types.h>
    #include<netinet/in.h>
    #include<sys/socket.h>
    #include<sys/wait.h>
    #include<unistd.h>
    #include<pthread.h>
    #define MAXLINE 100
    #define LISTENQ 20
    #define PORT 5000
    #define MAXFD 20
    void *get_client(void *);
    FILE *fp;
    int i,maxi=-1;//maxi表示当前client数组中最大的用户的i值
    int client[MAXFD];
    int main(void)
    {
    int connfd,listenfd,sockfd; //connfd存放accept函数的返回值,listenfd表示监听的套接口,
    //sockfd用于遍历client的数组
    socklen_t length;
    fp=fopen("student.txt","w");
    struct sockaddr_in server;
    struct sockaddr tcpaddr;
    pthread_t tid;
    listenfd=socket(AF_INET,SOCK_STREAM,0); //建立套接口并监听
    if(listenfd<0){
    printf("创建socket失败\n");
    exit(1);
    }
    memset(&server,0,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=htons(PORT);
    server.sin_addr.s_addr=htonl(INADDR_ANY);
    if( bind(listenfd,(struct sockaddr*)&server,sizeof(server))<0 )
    {
    printf("绑定套接口失败\n");
    exit(1);
    }
    length=sizeof(server);
    if(getsockname(listenfd,(struct sockaddr*)&server,&length)<0)
    {
    printf("取服务器的端口号失败\n"); //取得服务器的端口号
    exit(1);
    }
    for(i=0;i<MAXFD;i++)
    client[i]=-1; //initialize the client column
    listen(listenfd, LISTENQ);
    printf("服务器监听端口 %d...\n", ntohs(server.sin_port));
    printf("欢迎来到本聊天室\n");
    for(;;)
    {
    connfd=accept(listenfd, &tcpaddr, &length);
    for(i=0;i<MAXFD;i++)
    if(client[i]<0)
    {
    client[i]=connfd;
    break;
    } //用户链接成功后,在client数组中保存用户套接口号
    if(i==MAXFD-1)
    {
    printf("对不起,聊天室已经满了!\n"); //若此时以达到用户最大值,则退出链接
    exit(0);
    }
    if(i>maxi) maxi=i;
    pthread_create(&tid,NULL,&get_client,(void *)(intptr_t)connfd); //若链接成功,为此用户创建一个新线程
    } //运行get_client函数,处理用户请求
    }
    void *get_client(void *sockfd) //get_client函数
    {
    char buf[MAXLINE];
    int rev;
    if (((intptr_t)sockfd)<0)
    printf("\n新用户进入聊天室失败\n");
    else
    {
    printf("\n新用户进入聊天室...\n");
    do
    {
    memset(buf,0,sizeof(buf)); //初始化buffer
    if ((rev = recv((intptr_t)sockfd,buf,1024,0))<0)
    printf("\n读取用户消息失败\n");
    if (rev==0)
    printf("\n用户终止链接\n");
    else
    {
    printf("%s\n", buf); //若无异常,输出此用户消息
    for(i=0;i<=maxi;i++)
    send(client[i],buf,strlen(buf)+1,0);//将刚收到的用户消息分发给其他各用户
    fputs(buf,fp);
    }
    }while (rev != 0);
    fclose(fp);
    }
    close((intptr_t)sockfd);
    return(NULL);
    }
    client:
    #include<stdlib.h>
    #include<stdio.h>
    #include<string.h>
    #include<errno.h>
    #include<netdb.h>
    #include<sys/types.h>
    #include<netinet/in.h>
    #include<sys/socket.h>
    #include<sys/wait.h>
    #include<unistd.h>
    #include<pthread.h>
    #define TRUE 1
    #define PORT 5000
    int quit=0;
    void *get_server(void *);
    int main(void)
    {
    int connfd,snd,slenth;
    struct sockaddr_in server;
    struct hostent *hp;
    char honame[20],msg2[1024],msg1[1024],cln[102],qstr[]={"Quit"}; //
    pthread_t tid;
    printf("请输入服务器IP地址\n");
    scanf("%s*",honame);
    printf("创建套接口中\n");
    if((connfd= socket(AF_INET, SOCK_STREAM, 0))<0)
    printf("建立套接口失败\n");
    if ((hp= gethostbyname(honame))== NULL)
    {
    printf("获取服务器IP地址失败\n");
    exit(1);
    }
    else printf("套接口建立成功,链接服务器中...\n");
    memcpy(&server.sin_addr,hp->h_addr,hp->h_length);
    server.sin_family = AF_INET;
    server.sin_port=htons(PORT);
    if(connect(connfd,(struct sockaddr*)&server,sizeof(server))<0)
    {
    printf("链接服务器失败\n");
    exit(1);
    }
    printf("链接服务器成功\n");
    printf("欢迎来到聊天室\n");
    //聊天室
    printf("请输入你的用户昵称\n");
    scanf("%s",msg1);
    slenth=strlen(msg1);
    msg1[slenth]=':';
    msg1[slenth+1]='\0';
    strcpy(cln,msg1); //保存用户昵称在名为cln的数组中
    pthread_create(&tid,NULL,&get_server,(void *)(intptr_t)connfd);//为客户端创建一个线程用于监听,调用get_server函数
    printf("\n开始聊天吧 (\"Quit\"断开链接)\n");
    while(TRUE)
    {
    printf("\n");
    fgets(msg2,100,stdin);
    //scanf("%[^\n]",msg2);
    if(strcmp(msg2,qstr)==0)
    {
    close(connfd);
    quit=1; //若用户输入"Quit"字符则关闭发送套接口,并将quit置为1
    }
    else
    {
    strcat(msg1,msg2);//将消息前加上用户昵称
    snd=send(connfd,msg1,strlen(msg1)+1,0);//否则发送消息给服务器
    strcpy(msg1,cln);
    if(snd<0)
    printf("\n发送错误\n");
    }
    }
    }
    void *get_server(void* sockfd) //get_server函数,用于接受服务器转发的消息
    {
    char buf[1024];
    int rev;
    if(((intptr_t)sockfd)<0)
    {
    printf("\n接受服务器消息失败\n");
    }
    else
    {
    printf("\n\007\n");
    for(;;)
    {
    if(!quit)//只要quit不为1,则一直接受服务器消息
    {
    if ((rev = recv((intptr_t)sockfd,buf,1024,0))>0)
    printf("\n\007%s\n", buf);
    if (rev==0)
    {
    printf("\n服务器终止链接\n");
    quit=1;
    continue;
    }
    printf("\n");
    }
    else
    {
    close((intptr_t)sockfd);//关闭此套接口
    break;
    }
    }
    return(NULL);
    }
    }
    Makefile:

    target : server.o client.o
    gcc -o server server.o
    gcc -o client client.o
    server.o : server.c
    gcc -c -o server.o server.c
    client.o : client.c
    gcc -c -o client.o client.c
    clean :
    rm *.o server client
    .PHONY : clean

  • 相关阅读:
    <二>基于Django 简单后台管理页面
    单页面中使用vue和iview、echarts,引用组件
    vuecli更新
    vuex promise async await
    vue父子组件之间传值
    常用正则
    vue项目利用loadsh实现防抖和节流
    vue项目实现按钮的权限
    使用内存虚拟硬盘 提高ArcGIS server并发性能的一种方法
    esri联邦用户大会 总结
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/16196188.html
Copyright © 2020-2023  润新知