1472683788wan

1.实验项目名称:聊天室的设计与实现

2.实验目的:完成局域网内聊天功能,进一步掌握基于socket的编程方法和线程创建方法.

3.实验过程:

         通过socket 建立用户连接并传送用户输入的信息,分别来写客户端和服务器段,利用多线程来实现多用户模式,服务器随时准备接受客户端发送的消息,并判断该消息类型(私聊或群聊)来进行对应的转发工作,客户端随时接受来自服务器端的消息,从而实现消息的同步。

(1)开启服务器

(2)创建用户

(3)群聊的实现

(4)私聊的实现

(5)离开聊天室

 ser.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8024
int i=0;
int aa;
struct kehu {
    char name[10];//记录用户的姓名方便输出及辨认
    int haoma;//记录用户连接的sockfd值
    } ct[100];

//定义发送(拼音)函数,将消息通过结构体中存储的sockfd值发送给所有服务器
void fasong(char *qq,int d){
    int n=0;
    for(n;n<i;n++){
    //如果是调用(发送函数)本身的客户端直接跳过,不发送
        if(ct[n].haoma==d){
        continue;
    }
    write(ct[n].haoma,qq,strlen(qq));
    }
}

//制作客户端的线程
void *cli(void *bb)
{
    int aa=(*(int *)bb);
    int sql;
    char bk[200];
    char bj[200];
    char bj1[100];
    char bna[100];
    char ini[200]={};
    char s[10]={"@"};
    char *p;
    char *pi;
    int q;
    //先读一遍,接收账户名,发送给其他用户欢迎的提示
    read(aa,bna,sizeof(bna));
    sprintf(bj1,"欢迎%s进入聊天室",bna);
    fasong(bj1,aa);
    //将名字存入结构体
    strcpy(ct[i-1].name,bna);
    while(1)
    {
     q=read(aa,bk,sizeof(bk));
         printf("%s\n",bk);

         //客户端断开连接时,欢送,释放存储空间
         if(q==0){
         sprintf(bj,"欢送%s离开聊天室",bna);
         fasong(bj,aa);
         int u=0;
         //循环遍历至断开的客户端位置
         for(u;u<i;u++){
             if(ct[u].haoma==aa);
         break;
         }
         //将断开位置后的客户端结构体依次向前存储
         for(u;u<i;u++){
         strcpy(ct[i].name,ct[i+1].name);
         ct[i].haoma=ct[i+1].haoma;
         }
         //将指向创建结构体位置的 i 减一
         i-=1;
         break;
     }

          else{
       p=bk;
       sql=0;
           for(p;*p!=\'\0\';p++){
           //私聊功能,遍历内容中是否有@来确定是否为私聊
           if (*p==*s)
           {
                int l1=0;
        int l2=0;
        //以下内容
        for(l1;l1<i;l1++){
            pi=bk;
            for(pi;*pi!=\'\0\';pi++){
            if(*pi==*ct[l1].name){
                sprintf(bj,"%s对你说%s",bna,bk);
                write(ct[l1].haoma,bj,sizeof(bj));
                
                            break;
            }
            
            }
            
        }
                sql=1;
                break;
           }
         }    

         //正常聊天
      if(sql==1){
          continue;
      }
         sprintf(bj,"%s说:%s",bna,bk);
         fasong(bj,aa);
     
     
    }
    }
}

int main(){
    //建立网络连接
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd==-1){
        perror("failed socket");
        exit(-1);
        }
    printf("网络连接建立成功\n");

    //创建结构体
    struct sockaddr_in addr;
    addr.sin_family=AF_INET;
    addr.sin_port=htons(PORT);
    inet_aton("127.0.0.1",&addr.sin_addr);
    printf("结构体创建成功\n");
    
    //进行连接绑定
    int pp=bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));
    if(pp==-1){
        perror("failed bind");
        exit(-1);
        }
    
    //建立监听
    listen(sockfd,100);
    printf("正在初始化\n");

    //为连接做定义
    struct sockaddr_in from;
    socklen_t len = sizeof(from);
    int tid[10];
    
    printf("初始化成功\n");
    printf("等待连接\n");
    
    //循环等待
    while(1){
    //等待连接
    aa=accept(sockfd,(struct sockaddr *)&from,&len);
    //将用户的编号存入结构体
    ct[i].haoma=aa;
    pthread_t tid[i];
    pthread_create(&tid[i],NULL,cli,&aa);
    printf("%d号客户端连接成功\n",i);
    i+=1;
    }
}

cli.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8024
int sockfd;
//定义一个线程用于读取服务器发来的数据
void *rr(void *bb){
    while(1){
        char ba[200]={0};
        int aa=*(int *)bb;
        read(aa,ba,sizeof(ba));
        printf("%s\n",ba);
        }
}

int main(){
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    if (sockfd==-1){
        perror("failed socket");
        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);


    connect(sockfd,(struct sockaddr *)&addr,sizeof(addr));
    char bk[100];
    char bl[100];
    char bd[100]={};
    printf("*********************\n");
    printf("请输入您的账户名\n");
    scanf("%s",bk);
    printf("*********************\n");

    //将用户的账户名发送给服务器
    write(sockfd,bk,sizeof(bk));

    //通过复制来清空bk的内容
    strcpy(bk,bd);

    //制作读取线程
    pthread_t tid;
    pthread_create(&tid,NULL,rr,&sockfd);

    //循环读取并发送给服务器
    while(1){
        scanf("%s",bl);
        write(sockfd,bl,sizeof(bl));
    }
}

4.心得体会

  对socket定义及格式,select函数使用有了一定的了解,用socket实现多人聊天的思路,当服务器接收到来自某一客户端的数据时,直接转发给其他所有连接这的客户端,即完成了多人聊天;但是实现聊天室的私聊有bug,当@某人时会将私聊发出的消息再次群发给所有人,需要改进。

分类:

技术点:

相关文章: