网络编程项目(聊天室项目)

一、实现目标

一个在Linux下可以使用的聊天软件,要求至少实现如下功能:
1. 采用Client/Server架构
2. Client A 登陆聊天服务器前,需要注册自己的ID和密码
3. 注册成功后,Client A 就可以通过自己的ID和密码登陆聊天服务器
4. 多个Client X 可以同时登陆聊天服务器之后,与其他用户进行通讯聊天
5. Client A 成功登陆后可以查看当前聊天室内其他子啊先用户Client x
6. Client A 可以选择发消息给某个特定的 Client x,即“悄悄话”功能
7. Client A 可以选择发消息给全部的在线用户,即“群发消息”功能
8. Client A 在退出时需要保存聊天记录
9. Server 端维护一个所有登陆用户的聊天会的记录文件,以便查看

可以选择实现的附加功能:
1. Server 可以内建一个特殊权限的账号admin,用于管理聊天室
2. Admin 可以将某个Client X“踢出聊天室”
3. Admin 可以将某个Client X“设为只能旁听,不能发言”
4. Client 端发言增加表情符号,可以设置某些自定义的特殊组和来表达感情,如输入:),则会自动发送“XXX向大家做了个笑脸”
5. Client 段增加某些常用话语,可以对其中某些部分进行“姓名替换”,例如,输入/ClientA/welcome,则会自动发送“ClientA大侠,欢迎你来到咱们的聊天室”
Client.c源文件

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdlib.h>
#include <sqlite3.h> 
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>#define PORT  9999char myName[20];        // 保存用户名
char msg1[1024];        // 保存聊天信息sqlite3 * database;int flag1 = 0;          // 线程退出的判断条件(不退出)
int flag2 = 0;          // 文件传输确认信号(无接收)
int flag3 = 0;          // 存在文件接收请求的判断(不存在)
int flag4 = 0;          // 本地存储是否被禁言(未被禁言)// 协议
struct Msg
{char msg[1024];         // 消息内容int  cmd;               // 消息类型char filename[50];      // 保存文件名char toname[20];        // 接收者姓名char fromname[20];      // 发送者姓名int  sig;               // 用户状态(0:管理员、1:普通用户、2:被禁言)
};struct Msg msg;     // 全局变量两个线程共享// 注册/登录界面
void interface1()
{system("clear");printf ("\t*************************** 网络聊天室 *****************************\n");printf ("\t*                                                                  *\n");printf ("\t*                                                                  *\n");printf ("\t*                    1、 注册                                      *\n");                               printf ("\t*                    2、 登录                                      *\n");printf ("\t*                    q、 退出                                      *\n");printf ("\t*                                                                  *\n");printf ("\t*                                                                  *\n");printf ("\t*                                                 BY szw           *\n");printf ("\t********************************************************************\n\n");printf ("\t***** 请输入命令: ");}// 普通用户界面
void interface2()
{system("clear");printf ("\t*************************** 网络聊天室 *****************************\n");printf ("\t*                                                                  *\n");printf ("\t*                                                                  *\n");printf ("\t*                    1、 查看当前在线人数                          *\n");                               printf ("\t*                    2、 进入群聊界面                              *\n");printf ("\t*                    3、 进入私聊界面                              *\n");printf ("\t*                    4、 查看聊天记录                              *\n");printf ("\t*                    5、 文件传输                                  *\n");printf ("\t*                    6、 更改密码                                  *\n"); printf ("\t*                    7、 在线注销                                  *\n"); printf ("\t*                    Q、 退出聊天室 返回登录界面                   *\n");printf ("\t*                                                                  *\n");printf ("\t*                                                                  *\n");printf ("\t*                                                    BY szw        *\n");printf ("\t********************************************************************\n\n");printf ("\t***** 请输入命令: ");
}// 管理员界面
void interface3()
{system("clear");printf ("\t*************************** 网络聊天室 *****************************\n");printf ("\t*                                                                  *\n");printf ("\t*                                                                  *\n");printf ("\t*                    1、 查看当前在线人数                          *\n");                               printf ("\t*                    2、 进入群聊界面                              *\n");printf ("\t*                    3、 进入私聊界面                              *\n");printf ("\t*                    4、 查看聊天记录                              *\n");printf ("\t*                    5、 文件传输                                  *\n");printf ("\t*                    6、 更改密码                                  *\n"); printf ("\t*                    7、 在线注销                                  *\n"); printf ("\t*                    8、 管理员界面                                *\n");  printf ("\t*                    Q、 退出聊天室 返回登录界面                   *\n");printf ("\t*                                                                  *\n");printf ("\t*                                                                  *\n");printf ("\t*                                                    BY szw        *\n");printf ("\t********************************************************************\n\n");printf ("\t***** 请输入命令: ");
}// 用来保存收到的聊天信息
void keep_msg(char * msg1)
{// 打开数据库int ret = sqlite3_open("Histroy.db", &database);if (ret != SQLITE_OK){printf ("\t打开数据库失败\n");return;}// 往histroy表中添加信息char buf[100];char *errmsg = NULL;sprintf (buf, "insert into histroy values('%s','%s','%s')",msg.fromname,msg.toname,msg1);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("\t数据库操作失败:%s\n", errmsg);return;}
}// 接收文件
void receive()
{printf ("\n\t正在接收文件.....\n");int fd2 = open(msg.filename, O_WRONLY|O_CREAT, 0777);if (fd2 == -1){perror ("open fd2");return;}write (fd2, msg.msg, 1023);close (fd2);
}// 用来监听收到的信息
void *readMsg(void *v)
{int socketfd = (int)v;while(1){if (flag1 == 1)         // 判断线程的退出条件{flag1 = 0;          // 重置线程退出条件pthread_exit(NULL);} read (socketfd, &msg, sizeof(msg));switch(msg.cmd){case 9001:       // 群聊sprintf (msg1, "收到一条来自%s的群消息:\n\t%s", msg.fromname,msg.msg);printf ("\n\n\t%s\n", msg1);printf ("\n\t回车键返回  \n");keep_msg (msg1);break;case 9002:       // 私聊printf ("\n\t%s 发来一条消息:\n\t%s\n", msg.fromname, msg.msg);sprintf (msg1,"%s 向 %s 发送一条信息:\n\t%s",msg.fromname, msg.toname, msg.msg);printf ("\n\t回车键返回  \n");keep_msg (msg1);break;case 9003:      // 处理发送失败sleep(3);printf ("\n\t用户不在线或不存在,发送失败\n");printf ("\n\t回车键返回  \n");break;case 9004:      // 是否存在文件接收确认信号printf ("\n\n\t收到一条信息,输入任一字符进行回复:");fflush(stdout);flag3 = 1;break;  case 9005:      // 文件传输请求被拒绝printf ("\n\t您发送的文件传输请求已被拒绝\n");printf ("\n\t回车键返回  \n");break;case 9006:      // 文件传输请求已通过printf ("\n\t您发送的文件传输请求已通过,请打开文件传输界面进行文件传输\n");printf ("\n\t回车键返回  \n");break;case 9007:      // 接收文件if (flag2 != 1)printf ("\n\t已成功拦截 %s 给您发送的文件\n", msg.fromname);elsereceive();break;case 9008:      // 文件传输完成   printf ("\n\t%s 给您发送的文件已全部接收完毕,请及时查看\n", msg.fromname);printf ("\n\t回车键返回  \n");flag2 = 0;  // 重置文件传输确认信号break;case 9009:      // 密码修改成功printf ("\n\t密码修改成功!\n");sleep(1);break;case 9010:      // 密码输入有误printf ("\n\t密码输入有误,修改失败\n");usleep(1500000);break;  case 9011:      // 收到禁言信号printf ("\n\t您已被管理员禁言,将无法发送群聊信息\n");printf ("\n\t回车键返回  \n");flag4 = 1;break;case 9012:      // 收到结除禁言信号printf ("\n\t您已被管理员解除禁言\n");printf ("\n\t回车键返回  \n");flag4 = 0;break;case 9013:      // 收到被踢出信号printf ("\n\t您已被管理员踢出,即将退出聊天室....\n");//sleep (2);flag1 = 1; break;}usleep(400000);}
}// 查看当前在线人数
void display (int socketfd)
{msg.cmd = 1;write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求usleep(100000);printf ("\n\t当前在线人数为:%d\n", msg.cmd);printf ("\n\t回车键返回  \n");getchar();
}// 退出聊天室,返回登录界面
void quit_chatroom (int socketfd)
{msg.cmd = 10;strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送退出信号
}// 进入群聊界面
void chat1(int socketfd)
{if (flag4 == 1){printf ("\n\t您已被管理员禁言,无法发送群聊信息...\n");return;}msg.cmd = 2;strcpy (msg.fromname, myName);strcpy(msg.toname, "all");printf ("\n\t请输入您要发送的内容:\n\t");scanf ("%s",msg.msg);getchar();write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求printf ("\n\t发送完成,等待处理结果.....\n");
//  usleep (500000);
}// 进入私聊界面
void chat2(int socketfd)
{   msg.cmd = 3;strcpy (msg.fromname, myName);printf ("\n\t请输入您要发送的对象:\n\t");scanf ("%s",msg.toname);getchar();printf ("\t请输入您要发送的内容:\n\t");scanf ("%s",msg.msg);getchar();write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求printf ("\n\t发送完成,请稍候.....\n");usleep (500000);
}// 打印群聊历史记录
void chat1_hst()
{system("clear");printf ("\t*************************** 网络聊天室 *****************************\n\n\n");printf ("\t群聊历史记录:                                                      \n");// 打开数据库int ret = sqlite3_open("Histroy.db", &database);if (ret != SQLITE_OK){printf ("\t打开数据库失败\n");return;}// 获取histroy表中的信息char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from histroy";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}int i;for (i = 1+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], "all") == 0){printf ("\n\t%s\n", resultp[i+1]);}}sqlite3_free_table(resultp);// 关闭数据库sqlite3_close(database);
}// 打印私聊历史记录
void chat2_hst()
{system("clear");printf ("\t*************************** 网络聊天室 *****************************\n\n\n");printf ("\t私聊历史记录:\n");// 打开数据库int ret = sqlite3_open("Histroy.db", &database);if (ret != SQLITE_OK){printf ("\t打开数据库失败\n");return;}// 获取histroy表中的信息char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from histroy";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}int i;for (i = 1+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], "all") != 0){printf ("\n\t%s\n", resultp[i+1]);}}sqlite3_free_table(resultp);// 关闭数据库sqlite3_close(database);
}// 查看聊天记录
void dis_histroy(int socketfd)
{printf ("\n\t a、查看群聊记录\n\t b、查看个人聊天记录\n\t");printf ("\n\t***** 请选择: ");switch (getchar()){case 'a':chat1_hst();break;case 'b':chat2_hst();break;}printf ("\n\t回车键返回  ");getchar();
}// 确认传输对象
void convey_confirm(int socketfd)
{msg.cmd = 5;strcpy (msg.fromname, myName);printf ("\n\t请输入文件的传输对象:\n\t");scanf ("%s",msg.toname);getchar();printf ("\n\t传输请求发送完成,请稍等.....\n");write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求
}// 文件传输过程
void convey_chose(int socketfd)
{msg.cmd = 9007;strcpy (msg.toname, msg.fromname);strcpy (msg.fromname, myName);printf ("\n\t当前目录下的文件有: \n\n\t");fflush(stdout);system ("ls");printf ("\n\t请输入您要传送的文件名:  ");printf ("\n\t");scanf ("%s",msg.filename);getchar();// 打开要读的文件int fd1 = open(msg.filename, O_RDONLY);if (fd1 == -1){perror ("open fd1");return;}int ret = 0;flag1 = 1;          // 关闭线程while (ret = read (fd1, msg.msg, 1023)){if (ret == -1){perror("read");break;}printf ("\n\t正在传输文件,请稍候......\n");write (socketfd, &msg, sizeof(struct Msg));sleep(1);}msg.cmd = 9008;write (socketfd, &msg, sizeof(struct Msg));printf ("\n\t文件传输完成\n");close (fd1);// 重新开启一个线程pthread_t id;pthread_create(&id, NULL, readMsg, (void*)socketfd);pthread_detach(id); //  getchar();
}// 文件传输界面
void convey(int socketfd)
{system("clear");printf ("\t*************************** 网络聊天室 *****************************\n\n\n");printf ("\t                     1、传输对象确认\n");printf ("\t                     2、选择文件\n");printf ("\n\t***** 请选择: ");char ch[2];fgets(ch, 2, stdin);while (getchar()!= '\n');switch (ch[0]){case '1':       // 确认传输对象convey_confirm(socketfd);break;case '2':       // 文件选择convey_chose(socketfd);break;}printf ("\n\t回车键返回  ");getchar();
}// 更改密码
void change_pass(int socketfd)
{char ch[2];msg.cmd = 6;printf ("\n\t您是否确定需要修改密码?(y/n): ");fgets(ch, 2, stdin);while (getchar()!= '\n');if (ch[0] != 'y'){printf ("\n\t请稍候.....\n");usleep(700000);return;}printf ("\t请输入旧密码: ");scanf ("%s", msg.msg);getchar();printf ("\t请输入新密码: ");scanf ("%s", msg.filename);getchar();strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); // 向服务器发送注册信息printf ("\n\t正在校验数据,请稍候......\n");sleep(1);
}// 在线注销
void delete_user(int socketfd)
{msg.cmd = 8;printf ("\n\t正在处理注销操作......\n");write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求sleep(1);printf ("\t注销完成!\n");
}// 普通用户操作
void user_do (int socketfd)
{   char ch[2];while(1){interface2();if (flag3 == 1){printf ("\n\n\t%s 请求传输文件,是否接收?(y/n):", msg.fromname);fflush(stdout);fgets(ch, 2, stdin);while (getchar()!= '\n');if (ch[0] != 'y'){printf ("\n\t您已拒绝接受文件传输\n");printf ("\n\t回车键返回  \n");}else {printf ("\n\t您已接受文件传输请求\n");printf ("\n\t回车键返回  \n");flag2 = 1;}if (flag2 == 0){msg.cmd = 9005;                     // 不接受文件strcpy (msg.toname,msg.fromname);   // 修改信号发送对象strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); }else if (flag2 == 1){msg.cmd = 9006;                     // 接受文件strcpy (msg.toname,msg.fromname);   // 修改信号发送对象strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); }flag3 = 0;      // 重置是否存在文件接收请求的判断flag2 = 0;}fgets(ch, 2, stdin);while (getchar()!= '\n');  switch(ch[0]){case '1':     // 查看当前在线人数display(socketfd);break;case '2':     // 进入群聊界面 chat1(socketfd);printf ("\n\t回车键返回  \n");getchar();break;case '3':     // 进入私聊界面 chat2(socketfd);printf ("\n\t回车键返回  \n");getchar();break;case '4':     // 查看聊天记录dis_histroy(socketfd);getchar();break;case '5':     // 文件传输convey(socketfd);break;case '6':     // 更改密码change_pass(socketfd);break;case '7':     // 在线注销printf ("\n\t是否确认注销?(y/n):   ");fgets(ch, 2, stdin);while (getchar()!= '\n');if (ch[0] != 'y'){printf ("\n\t请稍候.....\n");usleep(700000);break;}delete_user(socketfd);case 'q':     // 退出聊天室 返回登录界面flag1 = 1;quit_chatroom(socketfd);printf ("\n\t正在退出,请稍候......\n");break;}if (flag1 == 1)   // 判断退出条件{break;}system("clear");}
}// 将成员禁言
void silent (int socketfd)
{msg.cmd = 9011;strcpy (msg.fromname, myName);printf ("\n\t请输入您要禁言的用户:\n\t");scanf ("%s",msg.toname);getchar();write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求printf ("\n\t操作完成,请稍候.....\n");usleep (500000);    
}// 将成员解除禁言
void silent_del (int socketfd)
{msg.cmd = 9012;strcpy (msg.fromname, myName);printf ("\n\t请输入您要解除禁言的用户:\n\t");scanf ("%s",msg.toname);getchar();write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求printf ("\n\t操作完成,请稍候.....\n");usleep (500000);        
}// 将成员踢出聊天室
void kickout (int socketfd)
{msg.cmd = 9013;strcpy (msg.fromname, myName);printf ("\n\t请输入您要踢出的用户:\n\t");scanf ("%s",msg.toname);getchar();write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求printf ("\n\t操作完成,请稍候.....\n");usleep (500000);        
}// 管理员权限
void supuser (int socketfd)
{system("clear");printf ("\t*************************** 网络聊天室 *****************************\n\n\n");printf ("\t                     1、将成员禁言\n");printf ("\t                     2、将成员解除禁言\n");printf ("\t                     3、将成员踢出聊天室\n");printf ("\n\t***** 请选择: ");char ch[2];fgets(ch, 2, stdin);while (getchar()!= '\n');switch (ch[0]){case '1':       // 将成员禁言silent(socketfd);break;case '2':       // 将成员解除禁言silent_del(socketfd);break;          case '3':       // 将成员踢出聊天室kickout(socketfd);break;}printf ("\n\t回车键返回  ");getchar();  
}// 管理员操作
void supuser_do (int socketfd)
{   char ch[2];while(1){interface3();if (flag3 == 1){printf ("\n\n\t%s 请求传输文件,是否接收?(y/n):", msg.fromname);fflush(stdout);fgets(ch, 2, stdin);while (getchar()!= '\n');if (ch[0] != 'y'){printf ("\n\t您已拒绝接受文件传输\n");printf ("\n\t回车键返回  \n");}else {printf ("\n\t您已接受文件传输请求\n");printf ("\n\t回车键返回  \n");flag2 = 1;}if (flag2 == 0){msg.cmd = 9005;                     // 不接受文件strcpy (msg.toname,msg.fromname);   // 修改信号发送对象strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); }else if (flag2 == 1){msg.cmd = 9006;                     // 接受文件strcpy (msg.toname,msg.fromname);   // 修改信号发送对象strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); }flag3 = 0;      // 重置是否存在文件接收请求的判断flag2 = 0;}fgets(ch, 2, stdin);while (getchar()!= '\n');  switch(ch[0]){case '1':     // 查看当前在线人数display(socketfd);break;case '2':     // 进入群聊界面 chat1(socketfd);printf ("\n\t回车键返回  \n");getchar();break;case '3':     // 进入私聊界面 chat2(socketfd);printf ("\n\t回车键返回  \n");getchar();break;case '4':     // 查看聊天记录dis_histroy(socketfd);getchar();break;case '5':     // 文件传输convey(socketfd);break;case '6':     // 更改密码change_pass(socketfd);break;case '8':     // 管理员权限操作supuser (socketfd);break;case '7':     // 在线注销printf ("\n\t是否确认注销?(y/n):   ");fgets(ch, 2, stdin);while (getchar()!= '\n');if (ch[0] != 'y'){printf ("\n\t请稍候.....\n");usleep(700000);break;}delete_user(socketfd);case 'q':     // 退出聊天室 返回登录界面flag1 = 1;quit_chatroom(socketfd);printf ("\n\t正在退出,请稍候......\n");break;}if (flag1 == 1)   // 判断退出条件{break;}system("clear");}
}// 登录
void log_in(int socketfd)
{char password[20];msg.cmd = 2;printf ("\n\t用户登录:\n");printf ("\t请输入用户名: ");scanf ("%s", myName);getchar();printf ("\t请输入密码: ");scanf ("%s", password);getchar();strcpy (msg.fromname, myName);strcpy (msg.msg, password);write (socketfd, &msg, sizeof(struct Msg)); // 向服务器发送登录请求read (socketfd, &msg, sizeof(struct Msg));  // 读取服务器的登录回应printf ("\n\t正在校验数据......\n");sleep(1);if (msg.cmd == 1002){printf ("\n\t验证通过,正在登录......\n");usleep(1500000);flag4 = msg.sig;        // 更新禁言状态// 线程分离,用来监听服务器返回信息pthread_t id;pthread_create(&id, NULL, readMsg, (void*)socketfd);pthread_detach(id);  user_do (socketfd);}else if (msg.cmd == 1003){printf ("\n\t验证通过,正在登录......\n");usleep(1500000);// 线程分离,用来监听服务器返回信息pthread_t id;pthread_create(&id, NULL, readMsg, (void*)socketfd);pthread_detach(id);  supuser_do (socketfd);}   else if (msg.cmd == -4){printf ("\n\t此账号已在别处登录\n");}else if (msg.cmd == -3){printf ("\n\t验证失败,请您确认信息后重新登录\n");}else if (msg.cmd == -2){printf ("\t验证失败,数据库打开失败\n");}else if (msg.cmd == -1){printf ("\t数据库操作失败\n");}usleep(1500000);
}// 注册(可注册管理员)
void reg(int socketfd)
{msg.cmd = 1;printf ("\t用户注册:\n");printf ("\t请输入用户名: ");scanf ("%s", myName);getchar();printf ("\t请输入密码: ");scanf ("%s", msg.msg);getchar();printf ("\t管理员: ");scanf ("%d", &msg.sig);getchar();  strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); // 向服务器发送注册信息read (socketfd, &msg, sizeof(struct Msg));  // 读取服务器的注册回应printf ("\n\t正在校验数据......\n");sleep(1);if (msg.cmd == 1001){printf ("\n\t注册成功!\n\t请稍候......\n");}else if (msg.cmd == -1){printf ("\t注册失败,该用户名已被注册\n");}else if (msg.cmd == -2){printf ("\t注册失败,数据库打开失败\n");}usleep(1500000);
}// 向服务器发送请求
void ask_server(int socketfd)
{char ch[2];while (1){interface1();fgets(ch, 2, stdin);while (getchar()!= '\n');switch(ch[0]){case '1':     // 注册reg(socketfd);break;case '2':     // 登录log_in(socketfd);break;case 'q':     // 退出exit(1);}system("clear");}
}int main(int argc, char **argv)
{// 打开数据库Histroy.dbint ret = sqlite3_open("Histroy.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");return -1;}// 创建 histroy 表char *errmsg = NULL;char *sql = "create table if not exists histroy(fromname TEXT,toname TEXT,msg TEXT)";ret = sqlite3_exec(database, sql, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return -1;}// 关闭数据库sqlite3_close(database);// 创建与服务器通信的套接字int socketfd = socket(AF_INET, SOCK_STREAM, 0);if (socketfd == -1){perror ("socket");return -1;}// 连接服务器struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family  = AF_INET;     // 设置地址族addr.sin_port    = htons(PORT); // 设置本地端口inet_aton(argv[1],&(addr.sin_addr));// 连接服务器,如果成功,返回0,如果失败,返回-1// 成功的情况下,可以通过socketfd与服务器进行通信ret = connect(socketfd, (struct sockaddr *)&addr, sizeof(addr));if (ret == -1){perror ("connect");return -1;}printf ("成功连上服务器\n");ask_server(socketfd);// 关闭套接字close(socketfd);return 0;
}

Server.c源文件

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdlib.h>
#include <sqlite3.h> #define PORT  9999sqlite3 * database;// 协议
struct Msg
{char msg[1024];         // 消息内容int  cmd;               // 消息类型char filename[50];      // 保存文件名char toname[20];        // 接收者姓名char fromname[20];      // 发送者姓名int  sig;               // 用户状态(0:管理员、1:普通用户、2:被禁言)
};// 初始化套接字,返回监听套接字
int init_socket()
{//1、创建socketint listen_socket = socket(AF_INET, SOCK_STREAM, 0);if (listen_socket == -1){perror ("socket");return -1;}// 2、命名套接字,绑定本地的ip地址和端口struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family  = AF_INET;     // 设置地址族addr.sin_port    = htons(PORT); // 设置本地端口addr.sin_addr.s_addr = htonl(INADDR_ANY);   // 使用本地的任意IP地址int  ret = bind(listen_socket,  (struct sockaddr *)&addr, sizeof(addr));if (ret == -1){perror ("bind");return -1;}// 3、监听本地套接字ret = listen(listen_socket, 5);if (ret == -1){perror ("listen");return -1;}printf ("服务器已就绪,等待客户端连接.......\n");return listen_socket;
}// 处理客户端连接,返回与连接上的客户端通信的套接字
int MyAccept(int listen_socket)
{// 4、接收连接struct sockaddr_in client_addr; // 用来保存客户端的ip和端口信息int len = sizeof(client_addr);int client_socket = accept(listen_socket, (struct sockaddr *)&client_addr, &len);if (client_socket == -1){perror ("accept");}printf ("成功接收一个客户端: %s\n", inet_ntoa(client_addr.sin_addr));return client_socket;
}// 查看当前在线人数
void display (int client_socket, struct Msg *msg)
{printf ("查看当前在线人数\n");// 确认flag参数// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 与User表中信息进行比对char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}int count = 0;int i;for (i = 3+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], "1") == 0){count++;}}// 返回在线人数msg->cmd = count;printf ("当前在线人数为:%d\n", msg->cmd);write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 关闭数据库sqlite3_close(database);printf ("操作完成,已关闭数据库\n");
}// 退出聊天室,返回登录界面
void quit_chatroom (int client_socket, struct Msg *msg)
{printf ("%s 退出聊天室\n", msg->fromname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");return;}char buf[100];char *errmsg = NULL;errmsg = NULL;sprintf (buf, "update user set flag = 0 where name = '%s'",msg->fromname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}sqlite3_close(database);printf ("登录状态修改完毕,已关闭数据库\n");write (client_socket, msg, sizeof(struct Msg));
}// 客户端发送群聊消息
void chat1 (int client_socket, struct Msg *msg)
{printf ("%s 发了一条群消息\n",msg->fromname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 获取数据库中的flag参数信息char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}int i;for (i = 3+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){// 查询所有在线的用户if(strcmp(resultp[i], "1") == 0){msg->cmd = 9001;    write (atoi(resultp[i-1]), msg, sizeof(struct Msg));    }}printf ("群消息已全部发送完成\n");
}// 客户端发送私聊消息
void chat2 (int client_socket, struct Msg *msg)
{printf ("%s 向 %s 发了一条消息\n",msg->fromname,msg->toname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 获取数据库中的flag参数信息,判断是否在线char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){msg->cmd = 9002;write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));
}// 处理确认文件传输对象
void convey_confirm (int client_socket, struct Msg *msg)
{printf ("%s 向 %s 发送文件传输请求\n",msg->fromname,msg->toname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");return;}// 获取数据库中的flag参数信息char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){msg->cmd = 9004;write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));
}// 用户不接受文件
void refuse (int client_socket, struct Msg *msg)
{printf ("%s 拒绝了 %s 的文件传输请求\n",msg->fromname,msg->toname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");return;}// 获取数据库中 toname 的套接字char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));
}// 用户接受文件
void accept_ (int client_socket, struct Msg *msg)
{printf ("%s 通过了 %s 的文件传输请求\n",msg->fromname,msg->toname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");return;}// 获取数据库中 toname 的套接字char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));
}// 处理文件传输
void convey_chose (int client_socket, struct Msg *msg)
{printf ("%s正在向%s传输文件......\n",msg->fromname,msg->toname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 获取数据库中的 flag 参数信息,判断是否在线char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 获取toname的套接字int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));
}// 文件传输完成
void convey_complete (int client_socket, struct Msg *msg)
{printf ("文件传输结束\n");// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 获取数据库中的 flag 参数信息,判断是否在线char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 获取toname的套接字int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));
}// 更改密码
void change_pass (int client_socket, struct Msg *msg)
{printf ("%s请求修改密码\n", msg->fromname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 与User表中信息进行比对char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from user";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->fromname)==0 && strcmp(resultp[i+1], msg->msg)==0){// 返回确认信息msg->cmd = 9009;printf ("%s 验证通过\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));// 修改密码char buf[100];errmsg = NULL;sprintf (buf, "update user set password = '%s' where name = '%s'",msg->filename,msg->fromname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}sqlite3_free_table(resultp);// 关闭数据库sqlite3_close(database);printf ("密码修改完成,已关闭数据库\n");return;}}   printf ("%s 验证不通过,密码输入有误\n", msg->fromname);msg->cmd = 9010;write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 关闭数据库sqlite3_close(database);printf ("操作完成,已关闭数据库\n");           }// 客户端请求在线注销
void delete_user (int client_socket, struct Msg *msg)
{printf ("即将处理用户注销\n");// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");return;}// 删除 user 表中的信息char buf[100];char *errmsg = NULL;sprintf (buf, "delete from user where name = '%s'", msg->fromname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}// 关闭数据库sqlite3_close(database);printf ("删除成功,已关闭数据库\n");
}// 处理禁言请求
void silent (int client_socket, struct Msg *msg)
{printf ("正在处理管理员 %s 对成员 %s 的禁言请求\n",msg->fromname,msg->toname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 获取数据库中的 flag 参数信息,判断是否在线char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 获取toname的套接字int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){msg->cmd =  9011;write (atoi(resultp[i+2]), msg, sizeof(struct Msg));char buf[100];errmsg = NULL;sprintf (buf, "update user set sig = 2 where name = '%s'",msg->toname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}sqlite3_close(database);printf ("禁言状态修改完毕,已关闭数据库\n");return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));sqlite3_close(database);printf ("用户不在线,修改失败,已关闭数据库\n");
}// 处理解除禁言请求
void silent_del (int client_socket, struct Msg *msg)
{printf ("正在处理管理员 %s 对成员 %s 的解除禁言请求\n",msg->fromname,msg->toname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 获取数据库中的 flag 参数信息,判断是否在线char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 获取toname的套接字int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){msg->cmd =  9012;write (atoi(resultp[i+2]), msg, sizeof(struct Msg));char buf[100];errmsg = NULL;sprintf (buf, "update user set sig = 1 where name = '%s'",msg->toname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}sqlite3_close(database);printf ("禁言状态修改完毕,已关闭数据库\n");return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));sqlite3_close(database);printf ("用户不在线,修改失败,已关闭数据库\n"); }// 处理踢出成员
void kickout (int client_socket, struct Msg *msg)
{printf ("正在处理管理员 %s 对成员 %s 的踢出请求\n",msg->fromname,msg->toname);// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 获取数据库中的 flag 参数信息,判断是否在线char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}// 获取toname的套接字int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){msg->cmd =  9013;write (atoi(resultp[i+2]), msg, sizeof(struct Msg));char buf[100];errmsg = NULL;sprintf (buf, "update user set flag = 0 where name = '%s'",msg->toname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return;}sqlite3_close(database);printf ("踢出完毕,已关闭数据库\n");return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));sqlite3_close(database);printf ("用户不在线,修改失败,已关闭数据库\n"); 
}// 处理用户操作请求函数
void user_do (int client_socket)
{struct Msg msg;int sig = 0;while(1){// 从客户端读一个结构体数据int ret = read(client_socket, &msg, sizeof(msg));if (ret == -1){perror ("read");break;}// 代表客户端退出if (ret == 0){printf ("客户端返回登录界面\n");break;}switch (msg.cmd){case 10:    // 退出聊天室,返回登录界面quit_chatroom(client_socket, &msg);sig = 1;break;case 1 :    // 查看当前在线人数display (client_socket, &msg);break;case 2 :    // 处理群聊消息 chat1 (client_socket, &msg);break;case 3 :    // 处理私聊消息 chat2 (client_socket, &msg);break;  case 5 :    // 处理确认文件传输对象convey_confirm (client_socket, &msg);break;case 6 :    // 更改密码change_pass (client_socket, &msg);break;case 8 :    // 处理在线注销delete_user (client_socket, &msg);break;case 9005 : // 用户不接受文件refuse (client_socket, &msg);break;case 9006 : // 用户接受文件accept_ (client_socket, &msg);break;case 9007 : // 处理文件传输convey_chose (client_socket, &msg);break;              case 9008 : // 文件传输完成convey_complete (client_socket, &msg);break;case 9011:  // 处理禁言请求silent (client_socket, &msg);break;case 9012:  // 处理解除禁言请求silent_del (client_socket, &msg);break;case 9013:  // 处理踢出成员kickout (client_socket, &msg);break;}if (sig == 1){printf("即将退出普通用户操作请求函数\n");break;}}
}// 处理客户端的登录请求
void log_in(int client_socket, struct Msg *msg)
{printf ("%s 请求登录\n", msg->fromname);// 将用户信息进行比对// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 与User表中信息进行比对char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from user";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->fromname)==0 && strcmp(resultp[i+1], msg->msg)==0){if (strcmp(resultp[i+3], "1") == 0){msg->cmd = -4;printf ("%s 已经在别处登录\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 关闭数据库sqlite3_close(database);printf ("操作完成,已关闭数据库\n");   return;}if (strcmp(resultp[i+4], "0") != 0){// 普通用户msg->cmd = 1002;msg->sig = atoi(resultp[i+4]);printf ("普通用户 %s 验证通过\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));}else {// 管理员msg->cmd = 1003;msg->sig = atoi(resultp[i+4]);printf ("管理员 %s 验证通过\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));}           // 修改在线状态、更新套接字char buf[100];errmsg = NULL;sprintf (buf, "update user set socket = '%d',flag = 1 where name = '%s'",client_socket,msg->fromname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}sqlite3_free_table(resultp);// 关闭数据库sqlite3_close(database);printf ("在线状态已更新,已关闭数据库\n");printf ("进入用户操作请求处理功能\n");user_do (client_socket);return;}}   printf ("%s 验证不通过\n", msg->fromname);msg->cmd = -3;write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 关闭数据库sqlite3_close(database);printf ("操作完成,已关闭数据库\n");
}// 处理客户端的注册请求
void reg(int client_socket, struct Msg *msg)
{printf ("%s 进行注册\n", msg->fromname);// 将用户进行保存// 打开数据库int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 往User表中添加信息char buf[100];char *errmsg = NULL;sprintf (buf, "insert into user values('%s','%s',%d,%d,%d)",msg->fromname,msg->msg,client_socket,0,msg->sig);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 返回确认信息msg->cmd = 1001;printf ("%s 注册成功\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));// 关闭数据库sqlite3_close(database);printf ("操作完成,已关闭数据库\n");
}// 线程的工作函数,即处理客户端请求的函数
void* hanld_client(void* v)
{int client_socket = (int)v;struct Msg msg;while(1){printf("处理客户端请求的函数函数已就绪\n");// 从客户端读一个结构体数据int ret = read(client_socket, &msg, sizeof(msg));if (ret == -1){perror ("read");break;}// 代表客户端退出if (ret == 0){printf ("客户端退出\n");break;}switch (msg.cmd){case 1 :    // 客户端进行注册reg(client_socket, &msg);break;case 2 :    // 客户端进行登录log_in(client_socket, &msg);break;}}close (client_socket);
}int main()
{// 打开数据库User.dbint ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打开数据库失败\n");return -1;}// 创建 user 表char *errmsg = NULL;char *sql = "create table if not exists user(name TEXT,password TEXT,socket INTEGER,flag INTEGER,sig INTEGER,primary key(name))";ret = sqlite3_exec(database, sql, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("数据库操作失败:%s\n", errmsg);return -1;}printf ("数据库准备就绪......\n");// 关闭数据库sqlite3_close(database);// 初始化套接字int listen_socket = init_socket();while (1){// 获取与客户端连接的套接字int client_socket = MyAccept(listen_socket);// 创建一个线程去处理客户端的请求,主线程依然负责监听pthread_t id;pthread_create(&id, NULL, hanld_client, (void *)client_socket);pthread_detach(id); // 线程分离}   close (listen_socket);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/448440.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CPU天梯图:2014年最新CPU性能天梯图

用户在组装电脑的前期需要考虑怎么选择适合自己的CPU&#xff0c;现在CPU性能强的比较贵&#xff0c;便宜的CPU性能又比较差&#xff0c;选择性价比高并且适合自己的处理器还真是比较花心思。在2014年的时候&#xff0c;最主流热门的AMD处理器是AMD A10-6800K&#xff0c;最新推…

解决: idea 修改 jsp 后,页面刷新无效

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 idea 修改 jsp 后浏览器访问无效。 解决&#xff1a;进入 idea 配置 修改部署方式&#xff1a; 修改 更新文件方式&#xff1a; OK了。

Python中的getpass模块

getpass模块用于输入密码时&#xff0c;隐藏密码字符 代码 import getpass name input("请输入你的名字&#xff1a;") passwd getpass.getpass("请输入你的密码&#xff1a;")print (name,passwd)   首先我们要import引入getpass模块&#xff0c;然后…

C++之命名空间

为什么要使用命名空间&#xff1f; 一个中大型软件往往由多名程序员共同开发&#xff0c;会使用大量的变量和函数&#xff0c;不可避免地会出现变量或函数的命名冲突。当所有人的代码都测试通过&#xff0c;没有问题时&#xff0c;将它们结合到一起就有可能会出现命名冲突。 …

如何做到每天写代码?

摘要&#xff1a;总有一大堆事情没有做完&#xff0c;没有时间和精力为业余项目写代码&#xff1f;不要着急&#xff0c;看看可汗学院计算机科学院院长John Resig怎么说。本文将教你如何保证在每天都能有时间给业余项目写代码。 你是否曾为业余项目没有进展而惆怅过&#xff1f…

Vue 实现前后端分离项目

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Vue实现前后端分离项目的初体验 经过之前学习的Vue的知识&#xff1a; vue基本指令vue组件vue-resourcevue路由 其实我们已经可以开始…

C++对C的一些加强和变化

实用性加强&#xff1a; int main() {// C语言中的变量都必须在作用域开始的位置定义&#xff01;&#xff01;// C中更强调语言的“实用性”&#xff0c;所有的变量都可以在需要使用时再定义。for (int i 0; i < 10; i){std::cout << i << std::endl;}return…

优秀Unix管理员的七个习惯

摘要&#xff1a;Unix系统管理员可能会很懒或喜欢优雅的解决方法&#xff0c;这就是他们的存在之美。一位优秀的Unix系统管理员有着自己的习惯&#xff1a;不会等到问题来找你、精通所使用的工具和系统、确定事情优先次序和喜欢优雅的解决方案但不迷失等。 优秀的Unix系统管理员…

Vue.js 极简小例:读值、样式调用、if判断、a 标签、点击事件、管道

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 写法&#xff1a; <template><div id"app"><!-- 三目运算符使用 ‘ok’ 的值定义在 data 中-->{{ ok …

【快写】基本思路及模板

快读也可以了解一下 先从C自带的输出开始吧 cout<<n<<endl;这是最基本的输出&#xff0c;适合初学者 &#xff08;虽然我到现在都还在用&#xff09; 然后稍微快一点的输出 printf("%d",n);这个就比较快速了&#xff0c;但是对于那种毒瘤题目 故意卡你的…

C++与C中const的比较以及const和define的比较

C与C中const的比较&#xff1a; C语言中 const修饰的变量是一个 常变量&#xff0c;本质还是变量&#xff0c;有自己的地址空间C编译器对const常量的处理 当碰见常量声明时&#xff0c;在符号表中放入常量 > 问题&#xff1a;那又如何解释取地址编译过程中若发现对const使…

中国古典十大悲剧

一.《窦娥冤》  《窦娥冤》——元关汉卿 山阴书生窦天章因无力偿还蔡婆的高利贷&#xff0c;把七岁的女儿窦娥送给蔡婆当童养媳来抵债。窦娥长大后与蔡婆儿子成婚&#xff0c;婚后两年蔡子病死。后来蔡婆向赛卢医索债&#xff0c;被赛卢医骗至郊外谋害&#xff0c;为流氓张驴…

解决: Elements in iteration expect to have ‘v-bind:key‘ directives

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 报错&#xff1a; Elements in iteration expect to have v-bind:key directives 原本写法&#xff1a; <li v-for"site in s…

回来太多事需要处理

出差回来&#xff0c;发现太多事需要处理现在每个项目都在Delay。且没有一个人是主动汇报项目的。这是非常不正常的现象。感觉有点累转载于:https://www.cnblogs.com/boriscao/archive/2005/09/03/229368.html

不该失去的,一块钱也不放弃

很多人都觉得&#xff0c;有钱人既然财力雄厚&#xff0c;花钱时必定毫不手软。然而&#xff0c;观察成功的CEO&#xff0c;你会发现&#xff0c;他们多数人花钱也花得小心&#xff0c;对于什么该花、值得花&#xff0c;算得十分精细。 华人首富、香港长江实业与和记黄埔董事局…

C++之引用

普通引用和常引用 1. 变量名的回顾 变量名实质上是一段连续存储空间的别名&#xff0c;是一个标号(门牌号) 程序中通过变量来申请并命名内存空间 通过变量的名字可以使用存储空间 问题&#xff1a;一段连续的内存空间是否只能有一个别名吗&#xff1f; 2. C引用的概念 引…

Vue.js 极简小例:数值计算、千米换算为米、九九乘法表、循环

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 代码&#xff1a; <template><div id"app"><!-- 千米和米换算 --><div id "computed_props&quo…

shiro框架的学习

权限控制是shiro最核心的东西 Shiro权限声明通常是使用以冒号分隔的表达式。一个权限表达式可以清晰的指定资源类型&#xff0c;允许的操作&#xff0c;可访问的数据。同时&#xff0c;Shiro权限表达式支持简单的通配符&#xff0c;可以更加灵活的进行权限设置。 下面以实例来说…

C++之内联函数

内联函数是一种特殊的函数&#xff0c;具有普通函数的特征&#xff08;参数检查&#xff0c;返回类型等&#xff09; 内联函数是对编译器的一种请求&#xff0c;因此编译器可能拒绝这种请求 内联函数由 编译器处理&#xff0c;直接将编译后的函数体插入调用的地方 宏代码片段…

妈妈培养天才的13绝招

作父母的&#xff0c;都希望自己的宝宝可以变得聪明、懂事&#xff0c;所以想尽办法去让宝宝上早教班、做早期智力开发……当然&#xff0c;这些做法对于开发宝宝智力能够起到一定的帮助。但是&#xff0c;千万别忽视您所能给予宝宝的家庭教育。    近日&#xff0c;日本一位…