基于Linux c 用socket和线程 实现的简易聊天室之服务器

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


#define PORTNUMBER 9994
#define MAXNUM 10
#define OK 1
#define ERROR 0




typedef  int Elementtype; 
typedef  int Status; 


//与客户端一致的结构体
typedef struct client
{
Elementtype id;
Elementtype flag;
Elementtype case_num;//服务器进行功能选择 
Elementtype case_numnext;//登录成功聊天功能选择
char name[100];
    char password[150];
//char content_c[1024];//接收客户端发送消息

}Client_message;


//定义一个服务器的结构体
typedef struct server
{   
    Elementtype i_s; 
    Elementtype num_s[10];

Elementtype case_snum;//服务器发送进行的功能  0注册成功,1登录失败,2普通用户登录,3管理员登录
Elementtype id__s;    //4私聊时查找ID有人,5私聊查找ID没人,6查询在线人数
  char name_s[100];
    char password_s[150];
//char content_s[1024];//服务器发送的消息缓存区

}Server_message;
//链表结构体
typedef struct node
{
int id_l;
int fd_l;
struct node *next;
}linkedlist;




Client_message msg_accept;//定义一个全局的结构体名字,接收客户端的结构体
Server_message msg_send;//定义一个全局的结构体名字,发送服务器的结构体




linkedlist *list;
//链表函数
linkedlist *createlinkedlist();
int getcount(linkedlist *list);
//void insert1(linkedlist *list, int id, int fd);
linkedlist *insert2(linkedlist *list, int id, int fd);
int queryfd(linkedlist *list, int id);
int queryid(linkedlist *list, int fd);
void printf_list(linkedlist *list);
linkedlist *dellinkedlist(linkedlist *list, int fd);


void *func(void * arg);


int newfd;//定义一个全局整形的套接字


int main(int argc, char *argv[])
{
    system("clear");

//message msg_accept;
int ret;

printf("服务器正在初始化......\n");
sleep(2);

int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == socket_fd)
{
perror("建立通信失败");
exit(1);
}

struct sockaddr_in server_addr;

memset(&server_addr, 0, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORTNUMBER);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

printf("初始化服务器成功......\n");
printf("正在启动服务器......\n");
    sleep(2);

if (-1 == bind(socket_fd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)))
{
perror("绑定地址失败");
exit(2);
}

if(-1 == listen(socket_fd, MAXNUM))//最大监听用户人数为10
{
perror("监听失败");
exit(3);
}

printf("服务器启动成功......\n");


sqlite3 *db;
ret = sqlite3_open("./server.db", &db);//打开数据库
if(ret != SQLITE_OK)
{
printf("打开数据库失败\n");
}

printf("打开数据库成功......\n");
printf("正在等待客户端的连接......\n");

ret = sqlite3_close(db);
if(ret != SQLITE_OK)
{
   printf("关闭数据库失败\n");
}

//创建一个单链表
list = createlinkedlist();
pthread_t pid;

while(1)
{
struct sockaddr_in client_addr;
int length = sizeof(struct sockaddr);

newfd = accept(socket_fd, (struct sockaddr *)(&client_addr), &length);
if (-1 == newfd)
{
perror("接收失败");
exit(1);
}
printf("客服端%d连上了服务器......\n",newfd);

pthread_create(&pid,NULL,(void*)func,(void*)newfd);

    }

//close(newfd);
return 0;
}




void *func(void * arg)
{
    int newfd = (int)arg;//强转为套接字类型
    char sendbuff[1024] = {0};//服务器发送信息
    char buff[1024] = {0};//把套接字先缓存到的区域
int ret;
static int num = 1000;//用作ID

// message *msg_accept = (message *)arg ;//把arg强转为结构体

while(1)
{

   ret = read(newfd, buff,1024);
if(-1 == ret)
{
            perror("读取错误");
            exit(1);
}  

memset(&msg_accept,0,sizeof(msg_accept));//清空结构体
   memcpy(&msg_accept,buff,sizeof(msg_accept));//把收到的信息转换为结构体

//printf("msg_accept.name = %s\t,msg_accept.password = %s\n",msg_accept.name,msg_accept.password);
//printf("msg_accept.case_num = %d\n",msg_accept.case_num);
switch(msg_accept.case_num)
{
case 1 : //客户请求注册
       {

printf("---------------------------------------------\n");
printf("客户端需要注册的名字为:  %s    密码 :%s\n",msg_accept.name,msg_accept.password);
printf("---------------------------------------------\n");      
 
sqlite3 *db;
char *errmsg;
ret = sqlite3_open("server.db",&db);
if(ret != SQLITE_OK)
{
perror("打开数据库失败");
exit(2);
}

char sql_insert[1024] = {0};

sprintf(sql_insert,"insert into server(id ,name,password) values(%d,'%s','%s');",num,msg_accept.name,msg_accept.password);
printf("----------------------以下信息已进入数据库-----------------------\n");
printf("%s\n",sql_insert);
printf("-----------------------------------------------------------------\n");
ret = sqlite3_exec(db,sql_insert,NULL,NULL,&errmsg);

if(ret != SQLITE_OK)
{
perror("插入数据库失败");
exit(3);
}
ret = sqlite3_close(db);
if(ret != SQLITE_OK)
{
perror("关闭数据库失败");
exit(4);
       }

           msg_send.case_snum = 0;
msg_send.id__s = num;

num++;

memset(sendbuff,0,1024);
memcpy(sendbuff,&msg_send,sizeof(msg_send));

ret = write(newfd ,sendbuff, 1024);
                if(-1 == ret)
                {
                    perror("写入失败");
                    exit(2);
                }  
break;

   }
           
            case 2: //客户请求登录
            {   
 
    printf("---------------------------------------------\n");
                 printf("有客户需要登录, 登录ID:%d    密码:%s  \n",msg_accept.id,msg_accept.password);
printf("---------------------------------------------\n");
 
sqlite3 *db;
char *errmsg;
int  row;
int  column;
char**result;
 
ret = sqlite3_open("server.db",&db);
if(ret != SQLITE_OK)
{
perror("打开数据库失败");
exit(2);
}
 
char sql_client[1024] = {0};

sprintf(sql_client,"select id,password from server where id = %d and password = '%s';",msg_accept.id,msg_accept.password);

ret = sqlite3_get_table(db, sql_client, &result, &row, &column, &errmsg);

if(ret != SQLITE_OK)
{
perror("查询数据库失败");
exit(3);
}
int i;
                 int j;
                 printf("-------查询结果如下--------\n");
            for(i = 1;i <= row;i++)
            {
                     for(j = 0;j < column;j++)
            {
            printf("%s|",result[i * column + j]);

            }
            printf("\n");
}
printf("---------------------------\n");
ret = sqlite3_close(db);
if(ret != SQLITE_OK)
{
perror("关闭数据库失败");
exit(4);
}
 
if(column == 0)
{
printf("你登录的信息有误,请重新登录.\n");
 
msg_send.case_snum = 1;
memset(sendbuff,0,1024);
    memcpy(sendbuff,&msg_send,sizeof(msg_send));


    ret = write(newfd ,sendbuff, 1024);
                     if(-1 == ret)
                     {
                         perror("写入失败");
                         exit(2);
                     }
  break;
}
 
else//登录成功
{    
printf("恭喜你登录成功.\n");
 
if(msg_accept.id == 1000)//管理员登录
{
memset(sendbuff,0,1024);
 
                         printf("管理员上线.\n");  
    msg_send.case_snum  = 3;//管理登录成功后发送到客户端的指令
        memcpy(sendbuff,&msg_send,sizeof(msg_send));
 
        ret = write(newfd ,sendbuff, 1024);
                         if(-1 == ret)
                         {
                             perror("写入失败");
                             exit(2);
                         }
    }
 
else //普通用户登录成功
{
 memset(sendbuff,0,1024);
 
                          printf("普通用户上线.\n");
 msg_send.case_snum  = 2;//普通用户登录成功后发送到客户端的指令
         memcpy(sendbuff,&msg_send,sizeof(msg_send));
 
         ret = write(newfd ,sendbuff, 1024);
                          if(-1 == ret)
                          {
                              perror("写入失败");
                              exit(2);
                          }
 
}
//插入信息到链表
list = insert2(list, msg_accept.id, newfd);
printf("现在在线人物信息 :\n");
printf_list(list);
printf("在线人数为:%d\n", getcount(list));

while(1)
{
                          memset(buff,0,1024);
                          ret = read(newfd,buff,1024);
 if(-1 == ret)
 {
 perror("读取失败");
 exit(1);
 }
 
                          memcpy(&msg_accept,buff,sizeof(msg_accept));
                          
                          
                          switch(msg_accept.case_numnext)
                          { 
                              case 1://查看当前人数
                              { 
     /*
     char str[1024] = {0};
 sprintf(str,"当前在线人数为: %d\n",count);      
                                 
                                  ret = write(newfd,str,1024);
 
 if(-1 == ret)
 {
 perror("写入人数失败");
 exit(2);
 }
                                   */
                                  int count = getcount(list);//用链表查看当前的人数
  
 memset(sendbuff ,0 ,1024);
 msg_send.id__s = count;//用作id_s临时记录下在线的人数 
 printf("count = %d\n",msg_send.id__s);
 
 msg_send.case_snum = 6;//查询在线人数
 //memcpy(sendbuff,&msg_send,sizeof(msg_send));
        
                 ret = write(newfd ,sendbuff, 1024);
                                  if(-1 == ret)
                                  {
                                      perror("写入失败");
                                      exit(2);
                                  }
 
 sleep(1);


                                  linkedlist *h = list;
                                  int temp = 0;
 
 while(h != NULL)
                                  {
 msg_send.num_s[temp] = h -> id_l;
                                      
 temp++;

                             h = h -> next;

 }
 
  msg_send.i_s = temp; 
  memcpy(sendbuff,&msg_send,sizeof(msg_send));
        
                  ret = write(newfd ,sendbuff, 1024);
                                   if(-1 == ret)
                                   {
                                       perror("写入失败");
                                       exit(2);
                                   }
                       
             break; 
 }  
                             
 case 2: //发送私聊
 {
 
 int send_newfd = queryfd(list, msg_accept.id);//查询私聊人物的FLAG
 //是否有此人
// printf("查到的客户端是: %d\n", send_newfd);
 int id_client = queryid(list,newfd);//查询发送消息人物的ID 
 //printf("id_client = %d\n",id_client);//打印他的ID
 
 if(send_newfd != 0)//有此人
 {
 
 printf("客户端%d  私聊客户端%d  消息为 : %s\n",newfd,send_newfd,msg_accept.name);
 
 memset(sendbuff ,0 ,1024);
 
                                      msg_send.id__s = send_newfd;//用作id_s临时记录下客户端的FLAG  
 msg_send.case_snum = 4;//查询有这个ID
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
                 
                     ret = write(newfd ,sendbuff, 1024);
                                      if(-1 == ret)
                                      {
                                          perror("写入失败");
                                          exit(2);
                                      }
     
 memset(sendbuff,0,1024);
 
 strcpy(msg_send.name_s,msg_accept.name);
 msg_send.case_snum = 7;//用于发送私聊消息的指令
 msg_send.id__s = id_client;//用于记录发送人的ID
 
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
 
 ret = write(send_newfd,sendbuff,1024);//发送给要私聊的人
 if(-1 == ret)
                                      {
                                          perror("写入失败");
                                          exit(2);
                                      }
 
 memset(sendbuff,0,1024);
 
 msg_send.case_snum = 8;//用于发聩消息发送成功了指令
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
 
     ret = write(newfd,sendbuff,1024);//发送给发起私聊的人
 
 if(-1 == ret)
                                      {
                                          perror("写入失败");
                                          exit(2);
                                      }
 
 
                                  }  
 else
 {
 printf("没有这个ID\n");
 
   memset(sendbuff ,0 ,1024);
 
 msg_send.case_snum = 5;//没有这个ID
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
                
                     ret = write(newfd ,sendbuff, 1024);
                                      if(-1 == ret)
                                      {
                                          perror("写入失败");
                                          exit(2);
                                      }
 
 }

 break;
 }
                              
 case 3: //发送群聊
 {  
     int id_client = queryid(list,newfd);//查询发送群聊消息人物的ID
 
 printf("客户端%d发起了群聊,内容是:%s\n",newfd,msg_accept.name);
 
 int i; 
 linkedlist *h = list;
 //把在线人数都遍历出来
 for(i = 0; i < getcount(list); i++)
 {
     if(h -> fd_l != newfd)
 {    
         memset(sendbuff, 0, 1024);
 
     strcpy(msg_send.name_s,msg_accept.name);//复制群聊的消息到服务器的结构体里面
         msg_send.case_snum = 9;//用于发送群聊消息的指令
         msg_send.id__s = id_client;//用于记录发送人的ID
 
         memcpy(sendbuff,&msg_send,sizeof(msg_send));
 
 ret = write(h -> fd_l, sendbuff, 1024);
 if(-1 == ret)
 {
 perror("write");
 exit(EXIT_FAILURE);
 }


 }
 h = h -> next;
 }

                         memset(sendbuff,0,1024);
 
 msg_send.case_snum = 10;//用于发聩消息发送成功了指令
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
 
 ret = write(newfd,sendbuff,1024);//发送给发起群聊的人
 
 if(-1 == ret)
                                  {
                                      perror("写入失败");
                                      exit(2);
                                  }
 
 break;
 }
 
 case 4: //客户请求发送文件
                              {

                     int ret;
 
 int accept_newfd = queryfd(list, msg_accept.id);//查询文件要发送到人物的FLAG

 int id_send = queryid(list,newfd);//查询发送文件的ID 
 
 printf("客户端%d请求发送文件给客户端%d,文件名是: %s\n",newfd,accept_newfd,msg_accept.name);
 
 memset(sendbuff,0,1024);
 //先把名字发给要接受文件的人
 
 msg_send.case_snum = 18;
 msg_send.id__s = id_send;
 strcpy(msg_send.name_s,msg_accept.name);
 
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
 
 ret = write(accept_newfd,sendbuff,1024);
 if(-1 == ret)
                                  {
                                       perror("写入失败\n");
                                       exit(1);   
 }
  
 //把内容发给要接受文件的人
while(1)
{

char buffer_file[1024];
memset(buffer_file, 0, 1024);//清空缓存

if(recv(newfd, buffer_file, 1024, 0) < 0)
{
perror("接收失败");
exit(1);

}

printf("内容是 :\n");
printf("%s\n",buffer_file);

if(send(accept_newfd, buffer_file, 1024, 0) < 0)
{
perror("发送失败");
exit(1);

}

if(0 == strncmp(buffer_file, "END", 3))
{

break;

}


}
 //把发送成功的消息发聩给发送者
                                  memset(sendbuff,1024,0);
                                  msg_send.case_snum = 19;
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
                                  
 ret = write(newfd,sendbuff,1024);
 if(-1 == ret)
                                  {
                                       perror("写入失败\n");
                                       exit(1);   
 }
                                   
 
 break;   
 }
 
 case 5: //客户请求下线
 {
 printf("客户端%d请求下线\n",newfd);
 
 list = dellinkedlist(list, newfd);
 printf_list(list);
 
 memset(sendbuff,0,1024);
 
 msg_send.case_snum = 11;//用于发聩消息发送成功了指令
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
 
 ret = write(newfd,sendbuff,1024);//发送给发起请求下线的人
 
 if(-1 == ret)
                                  {
                                      perror("写入失败");
                                      exit(2);
                                  }
 //break;
         goto out;
 }
 case 6://禁言
 {
 printf("管理员请求禁言,禁言的ID是%d\n",msg_accept.id);
 
 memset(sendbuff, 0, 1024);
 int jinyan_newfd = queryfd(list,msg_accept.id);//查询被禁言人的客户端
 
 
 msg_send.case_snum = 12;
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
   
 ret = write(jinyan_newfd,sendbuff,1024);//发送给被禁言的人
 
 if(-1 == ret)
                                  {
                                      perror("写入失败");
                                      exit(2);
                                  }
 
 //禁言成功反馈给管理员
 msg_send.case_snum = 13;
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
   
 ret = write(newfd,sendbuff,1024);//发送给被禁言的人
 
 if(-1 == ret)
                                  {
                                      perror("写入失败");
                                      exit(2);
                                  }
 
 

 break;
 }
 case 7://解禁
 {
 printf("管理员请求解禁,解禁的ID是%d\n",msg_accept.id);
 
 memset(sendbuff, 0, 1024);
 int jiejin_newfd = queryfd(list,msg_accept.id);//查询被禁言人的客户端
 
 
 msg_send.case_snum = 14;
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
   
 ret = write(jiejin_newfd,sendbuff,1024);//发送给被禁言的人
 
 if(-1 == ret)
                                  {
                                      perror("写入失败");
                                      exit(2);
                                  }
                                  
                                   
  //解禁成功反馈给管理员
 msg_send.case_snum = 15;
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
   
 ret = write(newfd,sendbuff,1024);//发送给管理员
 
 if(-1 == ret)
                                  {
                                      perror("写入失败");
                                      exit(2);
                                  }
 
 
 
 break;
 }
 case 8://踢人下线
 {
 printf("管理员请求踢人,被踢人的ID是%d\n",msg_accept.id);
 
 memset(sendbuff, 0, 1024);
 int tiren_newfd = queryfd(list,msg_accept.id);//查询被踢人的客户端
 
 
 msg_send.case_snum = 16;
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
   
 ret = write(tiren_newfd,sendbuff,1024);//发送给被踢的人
 
 if(-1 == ret)
                                  {
                                      perror("写入失败");
                                      exit(2);
                                  }
                                  
 
                                 
  //踢人成功反馈给管理员
 msg_send.case_snum = 17;
 memset(sendbuff, 0, 1024);
 memcpy(sendbuff,&msg_send,sizeof(msg_send));
   
 ret = write(newfd,sendbuff,1024);//发送给管理员
 
 if(-1 == ret)
                                  {
                                      perror("写入失败");
                                      exit(2);
                                  }
 
 break;
 }
 }  


}  
 
 
break;
}
 
    break;  
}
             
            case 3:
            {
                 printf("客户端%d请求退出\n",newfd);
goto outroom;  
}
     
        }//switch
    
out:
    
printf("-----------\n");

    }//while(1) 
 
    outroom:
    
close(newfd);


}


linkedlist *createlinkedlist()
{
linkedlist *h;
h = NULL;

return h;
}


linkedlist *dellinkedlist(linkedlist *list, int fd)
{
linkedlist *p = list -> next;
linkedlist *h = list;
if(list -> fd_l == fd)
{
free(h);
return list -> next;

}
else
{
while(p -> fd_l != fd)
{
p = p -> next;
h = h -> next;
}
h -> next = p -> next;
free(p);
return list;
}

}


linkedlist *insert2(linkedlist *list, int id, int fd)
{
linkedlist *head, *p;
head = list;
p = (linkedlist *)malloc(sizeof(linkedlist));
if(head == NULL)
{

head = p;
p -> next = NULL;
}
else
{
p -> next = head;
head = p;
}


p -> id_l = id;
p -> fd_l = fd;

return head;

}


int getcount(linkedlist *list)
{
linkedlist *h = list;
int count = 0;
while(h != NULL)
{
count++;
h = h -> next;
}
return count;
}


int queryid(linkedlist *list, int fd)
{
linkedlist *p, *h;
h = list;
while(h != NULL)
{
if(fd == h -> fd_l)
{
return h -> id_l;
}

h = h -> next;
}
}




int queryfd(linkedlist *list, int id)
{
linkedlist *h = list;
while(h != NULL)
{


if(id == h -> id_l)
{
return h -> fd_l;
}
h = h -> next;
}

return 0;
}


void printf_list(linkedlist *list)
{
linkedlist *h = list;
while(h != NULL)
{
printf("在线人物的ID为 :%d  FLAG :  %d\n", h ->id_l, h -> fd_l);
        h = h -> next;
}


printf("\n");
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值