├── README.md ├── ChatRome -- select ├── chatRome.db ├── server │ ├── Makefile │ ├── config.c │ ├── login.c │ ├── register.c │ ├── list.c │ ├── config.h │ ├── server.c │ └── chat.c ├── client │ ├── Makefile │ ├── register.c │ ├── login.c │ ├── config.c │ ├── interface.c │ ├── config.h │ ├── client.c │ └── chat.c └── readme ├── tcp_socket ├── config.h ├── server.c └── client.c ├── pthread_socket ├── config.h ├── client.c └── server.c ├── udp_socket ├── server.c └── client.c ├── epoll_socket ├── client.c └── server.c ├── poll_socket ├── client.c └── server.c └── select_socket ├── server.c └── client.c /README.md: -------------------------------------------------------------------------------- 1 | # Socket 2 | Linux网络编程 3 | -------------------------------------------------------------------------------- /ChatRome -- select/chatRome.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shineyr/Socket/HEAD/ChatRome -- select/chatRome.db -------------------------------------------------------------------------------- /tcp_socket/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * config.h 包含该tcp/ip套接字编程所需要的基本头文件,与server.c client.c位于同一目录下 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | const int MAX_LINE = 2048; 17 | const int PORT = 6000; 18 | const int BACKLOG = 10; 19 | const int LISTENQ = 6666; 20 | const int MAX_CONNECT = 20; 21 | 22 | 23 | -------------------------------------------------------------------------------- /pthread_socket/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * config.h 包含该tcp/ip套接字编程所需要的基本头文件,与server.c client.c位于同一目录下 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | const int MAX_LINE = 2048; 18 | const int PORT = 6001; 19 | const int BACKLOG = 10; 20 | const int LISTENQ = 6666; 21 | const int MAX_CONNECT = 20; 22 | 23 | 24 | -------------------------------------------------------------------------------- /ChatRome -- select/server/Makefile: -------------------------------------------------------------------------------- 1 | MYNAME = makefile 2 | CC = gcc 3 | 4 | objects = server.o register.o login.o list.o config.o chat.o 5 | 6 | server: $(objects) 7 | cc -g -o server $(objects) -lsqlite3 -lpthread 8 | 9 | server.o: server.c config.h 10 | cc -c server.c 11 | 12 | register.o: register.c config.h 13 | cc -c register.c 14 | 15 | login.o: login.c config.h 16 | cc -c login.c 17 | 18 | list.o: list.c config.h 19 | cc -c list.c 20 | 21 | config.o: config.c config.h 22 | cc -c config.c 23 | 24 | chat.o: chat.c config.h 25 | cc -c chat.c 26 | #比较稳健的clean做法,表示clean是一个伪目标 27 | .PHONY: clean 28 | 29 | #前面-的意思是:也许某些文件出现问题,忽略,继续执行 30 | clean: 31 | -rm server $(objects) 32 | 33 | -------------------------------------------------------------------------------- /ChatRome -- select/client/Makefile: -------------------------------------------------------------------------------- 1 | MYNAME = makefile 2 | CC = gcc 3 | 4 | objects = client.o config.o register.o login.o interface.o chat.o 5 | 6 | server: $(objects) 7 | cc -g -o client $(objects) -lsqlite3 -lpthread 8 | 9 | client.o: client.c config.h 10 | cc -c client.c 11 | 12 | register.o: register.c config.h 13 | cc -c register.c 14 | 15 | login.o: login.c config.h 16 | cc -c login.c 17 | 18 | interface.o: interface.c config.h 19 | cc -c interface.c 20 | 21 | chat.o: chat.c config.h 22 | cc -c chat.c 23 | 24 | config.o: config.c config.h 25 | cc -c config.c 26 | #比较稳健的clean做法,表示clean是一个伪目标 27 | .PHONY: clean 28 | 29 | #前面-的意思是:也许某些文件出现问题,忽略,继续执行 30 | clean: 31 | -rm client $(objects) 32 | 33 | -------------------------------------------------------------------------------- /ChatRome -- select/readme: -------------------------------------------------------------------------------- 1 | 项目简介: 2 | 采用I/O复用技术select实现socket通信,采用多线程负责每个客户操作处理,完成Linux下的多客户聊天室! 3 | 4 | OS:Ubuntu 15.04 5 | 6 | IDE:vim gcc make 7 | 8 | DB:Sqlite 3 9 | 10 | Time:2015-12-09 ~ 2012-12-21 11 | 12 | 项目功能架构: 13 | 14 | 1. 采用client/server结构; 15 | 2. 给出客户操作主界面(注册、登录、帮助和退出)、登录后主界面(查看在线列表、私聊、群聊、查看聊天记录、退出); 16 | 3. 多客户可同时连接服务器进行自己操作; 17 | 18 | ##服务器端## 19 | 1. server.c:服务器端主程序代码文件; 20 | 2. config.h:服务器端配置文件(包含需要的头文件、常量、数据结构及函数声明); 21 | 3. config.c:服务器端公共函数的实现文件; 22 | 4. list.c:链表实现文件,用于维护在线用户链表的添加、更新、删除操作; 23 | 5. register.c:服务器端实现用户注册; 24 | 6. login.c:服务器端实现用户登录; 25 | 7. chat.c:服务器端实现用户的聊天互动操作; 26 | 8. Makefile:服务器端make文件,控制台执行make命令可直接生成可执行文件server 27 | 28 | 29 | ##客户端## 30 | 1. client.c:客户端主程序代码文件; 31 | 2. config.h:客户端配置文件(包含需要的头文件、常量、数据结构及函数声明); 32 | 3. config.c:客户端公共函数的实现文件; 33 | 4. register.c:客户端实现用户注册; 34 | 5. login.c:客户端实现用户登录; 35 | 6. chat.c:客户端实现用户的聊天互动操作; 36 | 7. Makefile:客户端make文件,控制台执行make命令可直接生成可执行文件client; 37 | 8. interface.c:客户端界面文件; -------------------------------------------------------------------------------- /udp_socket/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | const int SERV_PORT = 6000; 9 | const int MAXLINE = 2048; 10 | 11 | void dg_echo(int sockfd , struct sockaddr *pcliaddr , socklen_t clilen) 12 | { 13 | int n; 14 | socklen_t len; 15 | char mesg[MAXLINE]; 16 | 17 | for( ; ;) 18 | { 19 | len = clilen; 20 | if((n = recvfrom(sockfd , mesg , MAXLINE , 0 , pcliaddr , &len))<0) 21 | { 22 | perror("recvfrom error"); 23 | exit(1); 24 | }//if 25 | 26 | if((n = sendto(sockfd , mesg , n , 0 , pcliaddr , len)) < 0) 27 | { 28 | perror("sendto error"); 29 | exit(1); 30 | }//if 31 | }//for 32 | 33 | } 34 | 35 | int main(int argc , char **argv) 36 | { 37 | int sockfd; 38 | struct sockaddr_in servaddr , cliaddr; 39 | 40 | bzero(&servaddr , sizeof(servaddr)); 41 | servaddr.sin_family = AF_INET; 42 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 43 | servaddr.sin_port = htons(SERV_PORT); 44 | 45 | if((sockfd = socket(AF_INET , SOCK_DGRAM , 0)) < 0) 46 | { 47 | perror("socket error"); 48 | exit(1); 49 | }//if 50 | 51 | if(bind(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr))) 52 | { 53 | perror("bind error"); 54 | exit(1); 55 | }//if 56 | 57 | dg_echo(sockfd , (struct sockaddr *)&cliaddr , sizeof(cliaddr)); 58 | } 59 | -------------------------------------------------------------------------------- /ChatRome -- select/client/register.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 客户端用户基本操作处理实现文件 3 | * 2015-12-10 yrr实现 4 | * 5 | ********************************************************************************/ 6 | 7 | #include "config.h" 8 | 9 | /********************************************* 10 | 函数名:registerUser 11 | 功能:用户注册函数实现 12 | 参数:套接字描述符 13 | 返回值:成功登陆返回SUCCESS 否则返回异常类型 14 | **********************************************/ 15 | int registerUser(int sockfd) 16 | { 17 | int ret; 18 | /*声明用户需要的注册信息*/ 19 | User user; 20 | char buf[MAX_LINE]; 21 | Message message; 22 | /*获取用户输入*/ 23 | printf("请输入注册用户名:\n"); 24 | memset(user.userName , 0 , sizeof(user.userName)); 25 | scanf("%s" , user.userName); 26 | printf("user.UserName = %s\n" , user.userName); 27 | 28 | printf("请输入注册用户密码:\n"); 29 | memset(user.password , 0 , sizeof(user.password)); 30 | scanf("%s" , user.password); 31 | printf("user.password = %s\n" , user.password); 32 | //当前用户允许发言 33 | user.speak = YES; 34 | 35 | memset(buf , 0 , MAX_LINE); 36 | memcpy(buf , &user , sizeof(user)); 37 | send(sockfd , buf , sizeof(buf) , 0); 38 | 39 | /*接收注册结果*/ 40 | memset(buf , 0 , MAX_LINE); 41 | recv(sockfd , buf , sizeof(buf) , 0); 42 | memset(&message , 0 , sizeof(message)); 43 | memcpy(&message , buf , sizeof(buf)); 44 | 45 | printf("%s\n",message.content); 46 | return message.msgRet; 47 | } 48 | -------------------------------------------------------------------------------- /ChatRome -- select/client/login.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 客户端用户登陆处理实现文件 3 | * 2015-12-14 yrr实现 4 | * 5 | ********************************************************************************/ 6 | 7 | #include "config.h" 8 | 9 | /********************************************* 10 | 函数名:loginUser 11 | 功能:用户登陆函数实现 12 | 参数:套接字描述符 13 | 返回值:成功登陆返回SUCCESS 否则返回异常类型 14 | **********************************************/ 15 | int loginUser(int sockfd) 16 | { 17 | int ret; 18 | /*声明用户登陆信息*/ 19 | User user; 20 | char buf[MAX_LINE]; 21 | Message message; 22 | /*获取用户输入*/ 23 | printf("请输入用户名:\n"); 24 | memset(user.userName , 0 , sizeof(user.userName)); 25 | scanf("%s" , user.userName); 26 | printf("user.UserName = %s\n" , user.userName); 27 | 28 | printf("请输入用户密码:\n"); 29 | memset(user.password , 0 , sizeof(user.password)); 30 | scanf("%s" , user.password); 31 | printf("user.password = %s\n" , user.password); 32 | 33 | /*发送用户登陆信息到服务器*/ 34 | memset(buf , 0 , MAX_LINE); 35 | memcpy(buf , &user , sizeof(user)); 36 | send(sockfd , buf , sizeof(buf) , 0); 37 | 38 | /*接收登陆结果*/ 39 | memset(buf , 0 , MAX_LINE); 40 | recv(sockfd , buf , sizeof(buf) , 0); 41 | memset(&message , 0 , sizeof(message)); 42 | memcpy(&message , buf , sizeof(buf)); 43 | 44 | printf("%s\n",message.content); 45 | 46 | /*如果登陆成功,则进入聊天界面*/ 47 | if(SUCCESS == message.msgRet) 48 | { 49 | enterChat(&user , sockfd); 50 | }//if 51 | return message.msgRet; 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /udp_socket/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | const int SERV_PORT = 6000; 9 | 10 | const int MAXLINE = 2048; 11 | void dg_cli(FILE *fp , int sockfd , const struct sockaddr *pservaddr , socklen_t servlen) 12 | { 13 | int n; 14 | char sendline[MAXLINE] , recvline[MAXLINE+1]; 15 | 16 | while(fgets(sendline , MAXLINE , fp) != NULL) 17 | { 18 | if(sendto(sockfd , sendline , strlen(sendline) , 0 , pservaddr , servlen) < 0) 19 | { 20 | perror("sendto error"); 21 | exit(1); 22 | }//if 23 | 24 | if( ( n = recvfrom(sockfd , recvline , MAXLINE , 0 , NULL , NULL)) < 0) 25 | { 26 | perror("recvfrom error"); 27 | exit(1); 28 | }//if 29 | 30 | recvline[n] = '\0'; 31 | fputs(recvline , stdout); 32 | 33 | }//while 34 | } 35 | 36 | int main(int argc , char **argv) 37 | { 38 | int sockfd , t; 39 | struct sockaddr_in servaddr; 40 | if(argc != 2) 41 | { 42 | perror("usage: udpcli "); 43 | exit(1); 44 | }//if 45 | 46 | bzero(&servaddr , sizeof(servaddr)); 47 | servaddr.sin_family = AF_INET; 48 | servaddr.sin_port = htons(SERV_PORT); 49 | if((t = inet_pton(AF_INET , argv[1], &servaddr.sin_addr)) <= 0) 50 | { 51 | perror("inet_pton error"); 52 | exit(1); 53 | }//if 54 | 55 | if((sockfd = socket(AF_INET , SOCK_DGRAM , 0)) < 0) 56 | { 57 | perror("socket error"); 58 | exit(1); 59 | }//if 60 | 61 | dg_cli(stdin , sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)); 62 | exit(0); 63 | } 64 | 65 | -------------------------------------------------------------------------------- /tcp_socket/server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * server.c为服务器端代码 3 | */ 4 | 5 | #include "config.h" 6 | 7 | int main(int argc , char **argv) 8 | { 9 | /*声明服务器地址和客户链接地址*/ 10 | struct sockaddr_in servaddr , cliaddr; 11 | 12 | /*声明服务器监听套接字和客户端链接套接字*/ 13 | int listenfd , connfd; 14 | pid_t childpid; 15 | 16 | /*声明缓冲区*/ 17 | char buf[MAX_LINE]; 18 | 19 | socklen_t clilen; 20 | 21 | /*(1) 初始化监听套接字listenfd*/ 22 | if((listenfd = socket(AF_INET , SOCK_STREAM , 0)) < 0) 23 | { 24 | perror("socket error"); 25 | exit(1); 26 | }//if 27 | 28 | /*(2) 设置服务器sockaddr_in结构*/ 29 | bzero(&servaddr , sizeof(servaddr)); 30 | 31 | servaddr.sin_family = AF_INET; 32 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //表明可接受任意IP地址 33 | servaddr.sin_port = htons(PORT); 34 | 35 | /*(3) 绑定套接字和端口*/ 36 | if(bind(listenfd , (struct sockaddr*)&servaddr , sizeof(servaddr)) < 0) 37 | { 38 | perror("bind error"); 39 | exit(1); 40 | }//if 41 | 42 | /*(4) 监听客户请求*/ 43 | if(listen(listenfd , LISTENQ) < 0) 44 | { 45 | perror("listen error"); 46 | exit(1); 47 | }//if 48 | 49 | /*(5) 接受客户请求*/ 50 | for( ; ; ) 51 | { 52 | clilen = sizeof(cliaddr); 53 | if((connfd = accept(listenfd , (struct sockaddr *)&cliaddr , &clilen)) < 0 ) 54 | { 55 | perror("accept error"); 56 | exit(1); 57 | }//if 58 | 59 | //新建子进程单独处理链接 60 | if((childpid = fork()) == 0) 61 | { 62 | close(listenfd); 63 | //str_echo 64 | ssize_t n; 65 | char buff[MAX_LINE]; 66 | while((n = read(connfd , buff , MAX_LINE)) > 0) 67 | { 68 | write(connfd , buff , n); 69 | } 70 | exit(0); 71 | }//if 72 | close(connfd); 73 | }//for 74 | 75 | /*(6) 关闭监听套接字*/ 76 | close(listenfd); 77 | } 78 | -------------------------------------------------------------------------------- /ChatRome -- select/client/config.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 基本配置文件实现 -- 包含所需头文件 3 | * 用户信息结构体定义 4 | * 在线用户链表定义 5 | ********************************************************************************/ 6 | #include "config.h" 7 | 8 | /************************************* 9 | 函数名:StateMsg 10 | 功能:根据操作结果得到相应的消息内容 11 | 参数:stateRet -- 操作结果整数值 12 | 返回值:操作结果字符串 13 | **************************************/ 14 | char *stateMsg(int stateRet) 15 | { 16 | switch(stateRet) 17 | { 18 | case EXCEED://已达服务器链接上限 19 | return "已达服务器链接上限!\n"; 20 | break; 21 | case SUCCESS: //成功 22 | return "操作成功!\n"; 23 | break; 24 | case FAILED: //失败 25 | return "操作失败!\n"; 26 | break; 27 | case DUPLICATEID: //重复的用户名 28 | return "重复的用户名!\n"; 29 | break; 30 | case INVALID: //不合法的用户名 31 | return "不合法输入!\n"; 32 | break; 33 | case ID_NOT_EXIST: //账号不存在 34 | return "账号不存在!\n"; 35 | break; 36 | case WRONGPWD: //密码错误 37 | return "密码错误!\n"; 38 | break; 39 | case ALREADY_ONLINE: 40 | return "该用户已在线!\n"; 41 | break; 42 | case ID_NOT_ONLINE: 43 | return "该用户不在线!\n"; 44 | break; 45 | case ALL_NOT_ONLINE: 46 | return "无人在线!\n"; 47 | break; 48 | case MESSAGE_SELF: //消息对象不能选择自己 49 | return "不能给自己发送消息\n"; 50 | break; 51 | default: 52 | return "未知操作结果!\n"; 53 | break; 54 | }//switch 55 | }; 56 | 57 | /************************************* 58 | 函数名:copyUser 59 | 功能:用户结构体对象拷贝操作 60 | 参数:user1--目标拷贝对象 user2--源拷贝对象 61 | 返回值:无 62 | **************************************/ 63 | void copyUser(User *user1 , User *user2) 64 | { 65 | strcpy((*user1).userName , (*user2).userName); 66 | strcpy((*user1).password , (*user2).password); 67 | (*user1).userAddr = (*user2).userAddr; 68 | (*user1).sockfd = (*user2).sockfd; 69 | (*user1).speak = (*user2).speak; 70 | strcpy((*user2).registerTime , (*user2).registerTime); 71 | 72 | } 73 | -------------------------------------------------------------------------------- /ChatRome -- select/server/config.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 基本配置文件实现 -- 包含所需头文件 3 | * 用户信息结构体定义 4 | * 在线用户链表定义 5 | ********************************************************************************/ 6 | #include "config.h" 7 | 8 | /************************************* 9 | 函数名:StateMsg 10 | 功能:根据操作结果得到相应的消息内容 11 | 参数:stateRet -- 操作结果整数值 12 | 返回值:操作结果字符串 13 | **************************************/ 14 | char *stateMsg(int stateRet) 15 | { 16 | switch(stateRet) 17 | { 18 | case EXCEED://已达服务器链接上限 19 | return "已达服务器链接上限!\n"; 20 | break; 21 | case SUCCESS: //成功 22 | return "操作成功!\n"; 23 | break; 24 | case FAILED: //失败 25 | return "操作失败!\n"; 26 | break; 27 | case DUPLICATEID: //重复的用户名 28 | return "重复的用户名!\n"; 29 | break; 30 | case INVALID: //不合法的用户名 31 | return "不合法输入!\n"; 32 | break; 33 | case ID_NOT_EXIST: //账号不存在 34 | return "账号不存在!\n"; 35 | break; 36 | case WRONGPWD: //密码错误 37 | return "密码错误!\n"; 38 | break; 39 | case ALREADY_ONLINE: 40 | return "该用户已在线!\n"; 41 | break; 42 | case ID_NOT_ONLINE: 43 | return "该用户不在线!\n"; 44 | break; 45 | case ALL_NOT_ONLINE: 46 | return "无人在线!\n"; 47 | break; 48 | case MESSAGE_SELF: //消息对象不能选择自己 49 | return "不能给自己发送消息\n"; 50 | break; 51 | default: 52 | return "未知操作结果!\n"; 53 | break; 54 | }//switch 55 | }; 56 | 57 | /************************************* 58 | 函数名:copyUser 59 | 功能:用户结构体对象拷贝操作 60 | 参数:user1--目标拷贝对象 user2--源拷贝对象 61 | 返回值:无 62 | **************************************/ 63 | void copyUser(User *user1 , User *user2) 64 | { 65 | strcpy((*user1).userName , (*user2).userName); 66 | strcpy((*user1).password , (*user2).password); 67 | (*user1).userAddr = (*user2).userAddr; 68 | (*user1).sockfd = (*user2).sockfd; 69 | (*user1).speak = (*user2).speak; 70 | strcpy((*user2).registerTime , (*user2).registerTime); 71 | 72 | } 73 | -------------------------------------------------------------------------------- /tcp_socket/client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * client.c为客户端代码 3 | */ 4 | 5 | #include "config.h" 6 | 7 | /*readline函数实现*/ 8 | ssize_t readline(int fd, char *vptr, size_t maxlen) 9 | { 10 | ssize_t n, rc; 11 | char c, *ptr; 12 | 13 | ptr = vptr; 14 | for (n = 1; n < maxlen; n++) { 15 | if ( (rc = read(fd, &c,1)) == 1) { 16 | *ptr++ = c; 17 | if (c == '\n') 18 | break; /* newline is stored, like fgets() */ 19 | } else if (rc == 0) { 20 | *ptr = 0; 21 | return(n - 1); /* EOF, n - 1 bytes were read */ 22 | } else 23 | return(-1); /* error, errno set by read() */ 24 | } 25 | 26 | *ptr = 0; /* null terminate like fgets() */ 27 | return(n); 28 | } 29 | 30 | 31 | int main(int argc , char ** argv) 32 | { 33 | /*声明套接字和链接服务器地址*/ 34 | int sockfd; 35 | struct sockaddr_in servaddr; 36 | 37 | /*判断是否为合法输入*/ 38 | if(argc != 2) 39 | { 40 | perror("usage:tcpcli "); 41 | exit(1); 42 | }//if 43 | 44 | /*(1) 创建套接字*/ 45 | if((sockfd = socket(AF_INET , SOCK_STREAM , 0)) == -1) 46 | { 47 | perror("socket error"); 48 | exit(1); 49 | }//if 50 | 51 | /*(2) 设置链接服务器地址结构*/ 52 | bzero(&servaddr , sizeof(servaddr)); 53 | servaddr.sin_family = AF_INET; 54 | servaddr.sin_port = htons(PORT); 55 | if(inet_pton(AF_INET , argv[1] , &servaddr.sin_addr) < 0) 56 | { 57 | printf("inet_pton error for %s\n",argv[1]); 58 | exit(1); 59 | }//if 60 | 61 | /*(3) 发送链接服务器请求*/ 62 | if( connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0) 63 | { 64 | perror("connect error"); 65 | exit(1); 66 | }//if 67 | 68 | /*(4) 消息处理*/ 69 | char sendline[MAX_LINE] , recvline[MAX_LINE]; 70 | while(fgets(sendline , MAX_LINE , stdin) != NULL) 71 | { 72 | write(sockfd , sendline , strlen(sendline)); 73 | 74 | if(readline(sockfd , recvline , MAX_LINE) == 0) 75 | { 76 | perror("server terminated prematurely"); 77 | exit(1); 78 | }//if 79 | 80 | if(fputs(recvline , stdout) == EOF) 81 | { 82 | perror("fputs error"); 83 | exit(1); 84 | }//if 85 | }//while 86 | 87 | /*(5) 关闭套接字*/ 88 | close(sockfd); 89 | } 90 | -------------------------------------------------------------------------------- /ChatRome -- select/client/interface.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 客户端界面设计 3 | * 2015-12-15 yrr实现 4 | * 5 | ********************************************************************************/ 6 | 7 | #include "config.h" 8 | 9 | /*************************************************** 10 | 函数名:mainInterface 11 | 功能:登录界面 12 | 传入参数:无 13 | 返回值:无 14 | ***************************************************/ 15 | int mainInterface() 16 | { 17 | 18 | printf("-------------------------------------\n"); 19 | printf(" 欢迎进入小Q聊天室~ \n"); 20 | printf(" 1.注册 \n"); 21 | printf(" 2.登陆 \n"); 22 | printf(" 3.帮助 \n"); 23 | printf(" 4.退出 \n"); 24 | printf("-------------------------------------\n\n\n"); 25 | } 26 | 27 | /*************************************************** 28 | 函数名:helpInterface 29 | 功能:主界面的帮助选项 30 | 传入参数:无 31 | 返回值:无 32 | ***************************************************/ 33 | int helpInterface() 34 | { 35 | 36 | printf("-------------------------------------\n"); 37 | printf(" 欢迎进入小帮助~ \n"); 38 | printf(" ^_^ \n"); 39 | printf(" 请在主界面选择操作~ \n"); 40 | printf(" ^_^ \n"); 41 | printf("-------------------------------------\n\n\n"); 42 | } 43 | 44 | /*************************************************** 45 | 函数名:helpInterface 46 | 功能:主界面的帮助选项 47 | 传入参数:无 48 | 返回值:无 49 | ***************************************************/ 50 | void chatInterface(char userName[]) 51 | { 52 | printf("------------------------------------------\n"); 53 | printf("你好,%s \n", userName); 54 | printf(" 1. 查看在线用户 \n"); 55 | printf(" 2. 私聊 \n"); 56 | printf(" 3. 群聊 \n"); 57 | printf(" 4. 查看聊天记录 \n"); 58 | printf(" 5. 退出 \n"); 59 | printf("请选择操作~ \n"); 60 | printf("------------------------------------------\n\n\n"); 61 | } 62 | 63 | -------------------------------------------------------------------------------- /ChatRome -- select/server/login.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 服务器处理用户基本操作处理实现文件 3 | * 2015-12-14 yrr实现 4 | * 5 | ********************************************************************************/ 6 | 7 | #include "config.h" 8 | 9 | /*声明全局变量 -- 在线用户链表*/ 10 | extern ListNode *userList; 11 | 12 | /************************************************** 13 | 函数名:loginUser 14 | 功能:用户登陆函数实现 15 | 参数:msg--用户发送的登陆消息 sockfd--套接字描述符 16 | 返回值:成功登陆返回SUCCESS 否则返回异常类型 17 | ****************************************************/ 18 | int loginUser(Message *msg , int sockfd) 19 | { 20 | int ret; 21 | /*声明用户信息*/ 22 | User user; 23 | char buf[MAX_LINE]; 24 | 25 | /*声明数据库变量*/ 26 | sqlite3 *db; 27 | sqlite3_stmt *stmt; 28 | const char *tail; 29 | 30 | /*声明sql语句存储变量*/ 31 | char sql[128]; 32 | 33 | /*存储操作结果消息*/ 34 | Message message; 35 | 36 | /*接收用户信息*/ 37 | recv(sockfd , buf , sizeof(user) , 0); 38 | memset(&user , 0 , sizeof(user)); 39 | memcpy(&user , buf , sizeof(buf)); 40 | user.userAddr = (*msg).sendAddr; 41 | user.sockfd = sockfd; 42 | 43 | /*查看在线用户列表,该用户是否已在线*/ 44 | if(isOnLine(userList , &user) == 1) 45 | return ALREADY_ONLINE; 46 | 47 | /*(1)打开数据库*/ 48 | ret = sqlite3_open(DB_NAME, &db); 49 | if(ret != SQLITE_OK) 50 | { 51 | printf("unable open database.\n"); 52 | return FAILED; 53 | }//if 54 | 55 | /*(2)检查登陆用户名和密码*/ 56 | memset(sql , 0 , sizeof(sql)); 57 | sprintf(sql , "select * from User where userName='%s' and password='%s';",user.userName , user.password); 58 | 59 | ret = sqlite3_prepare(db , sql , strlen(sql) , &stmt , &tail); 60 | if(ret != SQLITE_OK) 61 | { 62 | ret = sqlite3_step(stmt); 63 | sqlite3_finalize(stmt); 64 | sqlite3_close(db); 65 | printf("database select fail!\n"); 66 | return FAILED; 67 | }//if 68 | /*执行*/ 69 | ret = sqlite3_step(stmt); 70 | //如果有数据则返回SQLITE_ROW,当到达末尾返回SQLITE_DONE 71 | while(ret == SQLITE_ROW) 72 | { 73 | ret = sqlite3_step(stmt); 74 | sqlite3_finalize(stmt); 75 | sqlite3_close(db); 76 | ret = SUCCESS; 77 | /*如果登陆操作成功,添加到在线用户链表*/ 78 | userList = insertNode(userList , &user); 79 | return ret; 80 | }//while 81 | /*销毁句柄,关闭数据库*/ 82 | sqlite3_finalize(stmt); 83 | sqlite3_close(db); 84 | 85 | return FAILED; 86 | } 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /pthread_socket/client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 客户端代码 3 | */ 4 | #include "config.h" 5 | 6 | /*处理接收服务器消息函数*/ 7 | void *recv_message(void *fd) 8 | { 9 | int sockfd = *(int *)fd; 10 | while(1) 11 | { 12 | char buf[MAX_LINE]; 13 | memset(buf , 0 , MAX_LINE); 14 | int n; 15 | if((n = recv(sockfd , buf , MAX_LINE , 0)) == -1) 16 | { 17 | perror("recv error.\n"); 18 | exit(1); 19 | }//if 20 | buf[n] = '\0'; 21 | 22 | //若收到的是exit字符,则代表退出通信 23 | if(strcmp(buf , "byebye.") == 0) 24 | { 25 | printf("Server is closed.\n"); 26 | close(sockfd); 27 | exit(0); 28 | }//if 29 | 30 | printf("\nServer: %s\n", buf); 31 | }//while 32 | } 33 | 34 | 35 | int main(int argc , char **argv) 36 | { 37 | /*声明套接字和链接服务器地址*/ 38 | int sockfd; 39 | pthread_t recv_tid , send_tid; 40 | struct sockaddr_in servaddr; 41 | 42 | /*判断是否为合法输入*/ 43 | if(argc != 2) 44 | { 45 | perror("usage:tcpcli "); 46 | exit(1); 47 | }//if 48 | 49 | /*(1) 创建套接字*/ 50 | if((sockfd = socket(AF_INET , SOCK_STREAM , 0)) == -1) 51 | { 52 | perror("socket error"); 53 | exit(1); 54 | }//if 55 | 56 | /*(2) 设置链接服务器地址结构*/ 57 | bzero(&servaddr , sizeof(servaddr)); 58 | servaddr.sin_family = AF_INET; 59 | servaddr.sin_port = htons(PORT); 60 | if(inet_pton(AF_INET , argv[1] , &servaddr.sin_addr) < 0) 61 | { 62 | printf("inet_pton error for %s\n",argv[1]); 63 | exit(1); 64 | }//if 65 | 66 | /*(3) 发送链接服务器请求*/ 67 | if( connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0) 68 | { 69 | perror("connect error"); 70 | exit(1); 71 | }//if 72 | 73 | /*创建子线程处理该客户链接接收消息*/ 74 | if(pthread_create(&recv_tid , NULL , recv_message, &sockfd) == -1) 75 | { 76 | perror("pthread create error.\n"); 77 | exit(1); 78 | }//if 79 | 80 | /*处理客户端发送消息*/ 81 | char msg[MAX_LINE]; 82 | memset(msg , 0 , MAX_LINE); 83 | while(fgets(msg , MAX_LINE , stdin) != NULL) 84 | { 85 | if(strcmp(msg , "exit\n") == 0) 86 | { 87 | printf("byebye.\n"); 88 | memset(msg , 0 , MAX_LINE); 89 | strcpy(msg , "byebye."); 90 | send(sockfd , msg , strlen(msg) , 0); 91 | close(sockfd); 92 | exit(0); 93 | }//if 94 | if(send(sockfd , msg , strlen(msg) , 0) == -1) 95 | { 96 | perror("send error.\n"); 97 | exit(1); 98 | }//if 99 | 100 | 101 | }//while 102 | } 103 | -------------------------------------------------------------------------------- /pthread_socket/server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 服务器端代码实现 3 | */ 4 | 5 | #include "config.h" 6 | 7 | /*处理接收客户端消息函数*/ 8 | void *recv_message(void *fd) 9 | { 10 | int sockfd = *(int *)fd; 11 | while(1) 12 | { 13 | char buf[MAX_LINE]; 14 | memset(buf , 0 , MAX_LINE); 15 | int n; 16 | if((n = recv(sockfd , buf , MAX_LINE , 0)) == -1) 17 | { 18 | perror("recv error.\n"); 19 | exit(1); 20 | }//if 21 | buf[n] = '\0'; 22 | //若收到的是exit字符,则代表退出通信 23 | if(strcmp(buf , "byebye.") == 0) 24 | { 25 | printf("Client closed.\n"); 26 | close(sockfd); 27 | exit(1); 28 | }//if 29 | 30 | printf("\nClient: %s\n", buf); 31 | }//while 32 | } 33 | 34 | int main() 35 | { 36 | 37 | //声明套接字 38 | int listenfd , connfd; 39 | socklen_t clilen; 40 | //声明线程ID 41 | pthread_t recv_tid , send_tid; 42 | 43 | //定义地址结构 44 | struct sockaddr_in servaddr , cliaddr; 45 | 46 | /*(1) 创建套接字*/ 47 | if((listenfd = socket(AF_INET , SOCK_STREAM , 0)) == -1) 48 | { 49 | perror("socket error.\n"); 50 | exit(1); 51 | }//if 52 | 53 | /*(2) 初始化地址结构*/ 54 | bzero(&servaddr , sizeof(servaddr)); 55 | servaddr.sin_family = AF_INET; 56 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 57 | servaddr.sin_port = htons(PORT); 58 | 59 | /*(3) 绑定套接字和端口*/ 60 | if(bind(listenfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0) 61 | { 62 | perror("bind error.\n"); 63 | exit(1); 64 | }//if 65 | 66 | /*(4) 监听*/ 67 | if(listen(listenfd , LISTENQ) < 0) 68 | { 69 | perror("listen error.\n"); 70 | exit(1); 71 | }//if 72 | 73 | /*(5) 接受客户请求,并创建线程处理*/ 74 | 75 | clilen = sizeof(cliaddr); 76 | if((connfd = accept(listenfd , (struct sockaddr *)&cliaddr , &clilen)) < 0) 77 | { 78 | perror("accept error.\n"); 79 | exit(1); 80 | }//if 81 | 82 | printf("server: got connection from %s\n", inet_ntoa(cliaddr.sin_addr)); 83 | 84 | /*创建子线程处理该客户链接接收消息*/ 85 | if(pthread_create(&recv_tid , NULL , recv_message, &connfd) == -1) 86 | { 87 | perror("pthread create error.\n"); 88 | exit(1); 89 | }//if 90 | 91 | /*处理服务器发送消息*/ 92 | char msg[MAX_LINE]; 93 | memset(msg , 0 , MAX_LINE); 94 | while(fgets(msg , MAX_LINE , stdin) != NULL) 95 | { 96 | if(strcmp(msg , "exit\n") == 0) 97 | { 98 | printf("byebye.\n"); 99 | memset(msg , 0 , MAX_LINE); 100 | strcpy(msg , "byebye."); 101 | send(connfd , msg , strlen(msg) , 0); 102 | close(connfd); 103 | exit(0); 104 | }//if 105 | 106 | if(send(connfd , msg , strlen(msg) , 0) == -1) 107 | { 108 | perror("send error.\n"); 109 | exit(1); 110 | }//if 111 | }//while 112 | } 113 | 114 | 115 | -------------------------------------------------------------------------------- /epoll_socket/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define PORT 7777 16 | #define MAX_LINE 2048 17 | 18 | int max(int a , int b) 19 | { 20 | return a > b ? a : b; 21 | } 22 | 23 | /*readline函数实现*/ 24 | ssize_t readline(int fd, char *vptr, size_t maxlen) 25 | { 26 | ssize_t n, rc; 27 | char c, *ptr; 28 | 29 | ptr = vptr; 30 | for (n = 1; n < maxlen; n++) { 31 | if ( (rc = read(fd, &c,1)) == 1) { 32 | *ptr++ = c; 33 | if (c == '\n') 34 | break; /* newline is stored, like fgets() */ 35 | } else if (rc == 0) { 36 | *ptr = 0; 37 | return(n - 1); /* EOF, n - 1 bytes were read */ 38 | } else 39 | return(-1); /* error, errno set by read() */ 40 | } 41 | 42 | *ptr = 0; /* null terminate like fgets() */ 43 | return(n); 44 | } 45 | 46 | /*普通客户端消息处理函数*/ 47 | void str_cli(int sockfd) 48 | { 49 | /*发送和接收缓冲区*/ 50 | char sendline[MAX_LINE] , recvline[MAX_LINE]; 51 | while(fgets(sendline , MAX_LINE , stdin) != NULL) 52 | { 53 | write(sockfd , sendline , strlen(sendline)); 54 | 55 | bzero(recvline , MAX_LINE); 56 | if(readline(sockfd , recvline , MAX_LINE) == 0) 57 | { 58 | perror("server terminated prematurely"); 59 | exit(1); 60 | }//if 61 | 62 | if(fputs(recvline , stdout) == EOF) 63 | { 64 | perror("fputs error"); 65 | exit(1); 66 | }//if 67 | 68 | bzero(sendline , MAX_LINE); 69 | }//while 70 | } 71 | 72 | int main(int argc , char **argv) 73 | { 74 | /*声明套接字和链接服务器地址*/ 75 | int sockfd; 76 | struct sockaddr_in servaddr; 77 | 78 | /*判断是否为合法输入*/ 79 | if(argc != 2) 80 | { 81 | perror("usage:tcpcli "); 82 | exit(1); 83 | }//if 84 | 85 | /*(1) 创建套接字*/ 86 | if((sockfd = socket(AF_INET , SOCK_STREAM , 0)) == -1) 87 | { 88 | perror("socket error"); 89 | exit(1); 90 | }//if 91 | 92 | /*(2) 设置链接服务器地址结构*/ 93 | bzero(&servaddr , sizeof(servaddr)); 94 | servaddr.sin_family = AF_INET; 95 | servaddr.sin_port = htons(PORT); 96 | if(inet_pton(AF_INET , argv[1] , &servaddr.sin_addr) < 0) 97 | { 98 | printf("inet_pton error for %s\n",argv[1]); 99 | exit(1); 100 | }//if 101 | 102 | /*(3) 发送链接服务器请求*/ 103 | if(connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0) 104 | { 105 | perror("connect error"); 106 | exit(1); 107 | }//if 108 | 109 | /*调用消息处理函数*/ 110 | str_cli(sockfd); 111 | exit(0); 112 | } 113 | -------------------------------------------------------------------------------- /poll_socket/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define PORT 8888 16 | #define MAX_LINE 2048 17 | 18 | int max(int a , int b) 19 | { 20 | return a > b ? a : b; 21 | } 22 | 23 | /*readline函数实现*/ 24 | ssize_t readline(int fd, char *vptr, size_t maxlen) 25 | { 26 | ssize_t n, rc; 27 | char c, *ptr; 28 | 29 | ptr = vptr; 30 | for (n = 1; n < maxlen; n++) { 31 | if ( (rc = read(fd, &c,1)) == 1) { 32 | *ptr++ = c; 33 | if (c == '\n') 34 | break; /* newline is stored, like fgets() */ 35 | } else if (rc == 0) { 36 | *ptr = 0; 37 | return(n - 1); /* EOF, n - 1 bytes were read */ 38 | } else 39 | return(-1); /* error, errno set by read() */ 40 | } 41 | 42 | *ptr = 0; /* null terminate like fgets() */ 43 | return(n); 44 | } 45 | 46 | /*普通客户端消息处理函数*/ 47 | void str_cli(int sockfd) 48 | { 49 | /*发送和接收缓冲区*/ 50 | char sendline[MAX_LINE] , recvline[MAX_LINE]; 51 | while(fgets(sendline , MAX_LINE , stdin) != NULL) 52 | { 53 | write(sockfd , sendline , strlen(sendline)); 54 | 55 | bzero(recvline , MAX_LINE); 56 | if(readline(sockfd , recvline , MAX_LINE) == 0) 57 | { 58 | perror("server terminated prematurely"); 59 | exit(1); 60 | }//if 61 | 62 | if(fputs(recvline , stdout) == EOF) 63 | { 64 | perror("fputs error"); 65 | exit(1); 66 | }//if 67 | 68 | bzero(sendline , MAX_LINE); 69 | }//while 70 | } 71 | 72 | int main(int argc , char **argv) 73 | { 74 | /*声明套接字和链接服务器地址*/ 75 | int sockfd; 76 | struct sockaddr_in servaddr; 77 | 78 | /*判断是否为合法输入*/ 79 | if(argc != 2) 80 | { 81 | perror("usage:tcpcli "); 82 | exit(1); 83 | }//if 84 | 85 | /*(1) 创建套接字*/ 86 | if((sockfd = socket(AF_INET , SOCK_STREAM , 0)) == -1) 87 | { 88 | perror("socket error"); 89 | exit(1); 90 | }//if 91 | 92 | /*(2) 设置链接服务器地址结构*/ 93 | bzero(&servaddr , sizeof(servaddr)); 94 | servaddr.sin_family = AF_INET; 95 | servaddr.sin_port = htons(PORT); 96 | if(inet_pton(AF_INET , argv[1] , &servaddr.sin_addr) < 0) 97 | { 98 | printf("inet_pton error for %s\n",argv[1]); 99 | exit(1); 100 | }//if 101 | 102 | /*(3) 发送链接服务器请求*/ 103 | if(connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0) 104 | { 105 | perror("connect error"); 106 | exit(1); 107 | }//if 108 | 109 | /*调用消息处理函数*/ 110 | str_cli(sockfd); 111 | exit(0); 112 | } 113 | -------------------------------------------------------------------------------- /ChatRome -- select/client/config.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 基本配置文件 -- 包含所需头文件 3 | * 用户信息结构体定义 4 | * 在线用户链表定义 5 | ********************************************************************************/ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include /*使用memcpy所需的头文件*/ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | /*FD_SETSIZE定义描述符集的大小,定义在sys/types.h中*/ 31 | #ifndef FD_SETSIZE 32 | #define FD_SETSIZE 256 33 | #endif 34 | 35 | #define MAX_LINE 8192 36 | #define PORT 8888 37 | #define LISTENEQ 6000 38 | 39 | /*预定义数据库名称*/ 40 | #define DB_NAME "/home/yangrui/projects/Socket/ChatRome_select/chatRome.db" 41 | 42 | /*标志*/ 43 | enum Flag{ 44 | YES, /*代表被禁言*/ 45 | NO /*代表没有被禁言*/ 46 | }; 47 | 48 | /*定义服务器--客户端 消息传送类型*/ 49 | enum MessageType{ 50 | REGISTER = 1, /*注册请求*/ 51 | LOGIN, /*登陆请求*/ 52 | HELP, /*帮助请求*/ 53 | EXIT, /*退出请求*/ 54 | VIEW_USER_LIST, /*查看在线列表*/ 55 | GROUP_CHAT, /*群聊请求*/ 56 | PERSONAL_CHAT, /*私聊请求*/ 57 | VIEW_RECORDS, /*查看聊天记录请求*/ 58 | RESULT, /*结果消息类型*/ 59 | UNKONWN /*未知请求类型*/ 60 | }; 61 | 62 | /*定义操作结果 */ 63 | enum StateRet{ 64 | EXCEED, //已达服务器链接上限 65 | SUCCESS, //成功 66 | FAILED, //失败 67 | DUPLICATEID, //重复的用户名 68 | INVALID, //不合法的用户名 69 | ID_NOT_EXIST, //账号不存在 70 | WRONGPWD, //密码错误 71 | ALREADY_ONLINE, //已经在线 72 | ID_NOT_ONLINE, //账号不在线 73 | ALL_NOT_ONLINE, //无人在线 74 | MESSAGE_SELF //消息对象不能选择自己 75 | }; 76 | 77 | 78 | /*定义服务器 -- 客户端 消息传送结构体*/ 79 | typedef struct _Message{ 80 | char content[2048]; /*针对聊天类型的消息,填充该字段*/ 81 | int msgType; /*消息类型 即为MessageType中的值*/ 82 | int msgRet; /*针对操作结果类型的消息,填充该字段*/ 83 | struct sockaddr_in sendAddr; /*发送者IP*/ 84 | struct sockaddr_in recvAddr; 85 | char sendName[20]; /*发送者名称*/ 86 | char recvName[20]; /*接收者名称*/ 87 | char msgTime[20]; /*消息发送时间*/ 88 | }Message; 89 | 90 | //用户信息结构体 91 | typedef struct _User{ 92 | char userName[20]; //用户名 93 | char password[20]; 94 | struct sockaddr_in userAddr; //用户IP地址,选择IPV4 95 | int sockfd; //当前用户套接字描述符 96 | int speak; //是否禁言标志 97 | char registerTime[20]; //记录用户注册时间 98 | }User; 99 | 100 | /*定义用户链表结构体*/ 101 | typedef struct _ListNode{ 102 | User user; 103 | struct _ListNode *next; 104 | }ListNode; 105 | 106 | 107 | /*定义在线用户链表*/ 108 | ListNode *userList; 109 | 110 | extern char *stateMsg(int stateRet); 111 | extern void copyUser(User *user1 , User *user2); 112 | 113 | -------------------------------------------------------------------------------- /ChatRome -- select/server/register.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 服务器处理用户基本操作处理实现文件 3 | * 2015-12-10 yrr实现 4 | * 5 | ********************************************************************************/ 6 | 7 | #include "config.h" 8 | 9 | /********************************************* 10 | 函数名:registerUser 11 | 功能:用户注册函数实现 12 | 参数:msg--用户发送的注册消息 sockfd--套接字描述符 13 | 返回值:成功登陆返回SUCCESS 否则返回异常类型 14 | **********************************************/ 15 | int registerUser(Message *msg , int sockfd) 16 | { 17 | int ret; 18 | /*声明用户需要的注册信息*/ 19 | User user; 20 | char buf[MAX_LINE]; 21 | 22 | /*声明数据库变量*/ 23 | sqlite3 *db; 24 | sqlite3_stmt *stmt; 25 | const char *tail; 26 | 27 | /*声明sql语句存储变量*/ 28 | char sql[128]; 29 | 30 | /*当前系统时间*/ 31 | time_t timeNow; 32 | 33 | /*存储操作结果消息*/ 34 | Message message; 35 | 36 | /*接收用户注册信息*/ 37 | recv(sockfd , buf , sizeof(user) , 0); 38 | memset(&user , 0 , sizeof(user)); 39 | memcpy(&user , buf , sizeof(buf)); 40 | user.userAddr = (*msg).sendAddr; 41 | user.sockfd = sockfd; 42 | 43 | if(strlen(user.userName) > 20) 44 | { 45 | return INVALID; 46 | }//if 47 | 48 | /*(1)打开数据库*/ 49 | ret = sqlite3_open(DB_NAME, &db); 50 | if(ret != SQLITE_OK) 51 | { 52 | printf("unable open database.\n"); 53 | return FAILED; 54 | }//if 55 | printf("Opened database successfully.\n"); 56 | 57 | /*(2)检查要注册用户名是否已存在?*/ 58 | memset(sql , 0 , sizeof(sql)); 59 | sprintf(sql , "select * from User where userName='%s';",(user.userName)); 60 | 61 | ret = sqlite3_prepare(db , sql , strlen(sql) , &stmt , &tail); 62 | if(ret != SQLITE_OK) 63 | { 64 | ret = sqlite3_step(stmt); 65 | sqlite3_finalize(stmt); 66 | sqlite3_close(db); 67 | printf("database select fail!\n"); 68 | return FAILED; 69 | }//if 70 | /*执行*/ 71 | ret = sqlite3_step(stmt); 72 | //如果有数据则返回SQLITE_ROW,当到达末尾返回SQLITE_DONE 73 | while (ret == SQLITE_ROW) 74 | { 75 | ret = sqlite3_step(stmt); 76 | sqlite3_finalize(stmt); 77 | sqlite3_close(db); 78 | return FAILED; 79 | } 80 | /*销毁句柄,关闭数据库*/ 81 | sqlite3_finalize(stmt); 82 | 83 | /*执行插入操作*/ 84 | memset(sql , 0 , sizeof(sql)); 85 | time(&timeNow); 86 | sprintf(sql , "insert into User(userName , password , userAddr , sockfd , speak , registerTime)\ 87 | values('%s','%s','%s',%d, %d , '%s');",user.userName , user.password , 88 | inet_ntoa(user.userAddr.sin_addr),user.sockfd , YES, asctime(gmtime(&timeNow))); 89 | 90 | ret = sqlite3_prepare(db , sql , strlen(sql) , &stmt , &tail); 91 | if(ret != SQLITE_OK) 92 | { 93 | ret = sqlite3_step(stmt); 94 | sqlite3_finalize(stmt); 95 | sqlite3_close(db); 96 | return FAILED; 97 | }//if 98 | 99 | /*顺利注册*/ 100 | ret = sqlite3_step(stmt); 101 | sqlite3_finalize(stmt); 102 | sqlite3_close(db); 103 | /*注册成功*/ 104 | return SUCCESS; 105 | } 106 | -------------------------------------------------------------------------------- /ChatRome -- select/server/list.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 服务器端 在线客户 链表结构与操作 3 | * 2015-12-14 yrr实现 4 | * 5 | ********************************************************************************/ 6 | 7 | #include "config.h" 8 | 9 | /**************************************************** 10 | 函数名:insertNode 11 | 功能:插入在线用户链表新节点 12 | 参数:list--当前在线用户链表 elem--要插入的元素 13 | 返回值:返回创建的链表 14 | ***************************************************/ 15 | ListNode* insertNode(ListNode *list , User *user) 16 | { 17 | /*建立新节点*/ 18 | ListNode *node = (ListNode *)calloc(1, sizeof(ListNode)); 19 | 20 | copyUser(&(node->user) , user); 21 | 22 | node->next = NULL; 23 | if(list == NULL) 24 | { 25 | list = node; 26 | }//if 27 | else{ 28 | ListNode *p = list; 29 | while(p->next != NULL) 30 | { 31 | p = p->next; 32 | }//while 33 | p->next = node; 34 | }//else 35 | 36 | printf("更新在线列表!\n"); 37 | return list; 38 | } 39 | 40 | /**************************************************** 41 | 函数名:isOnLine 42 | 功能:查看某用户是否在线 43 | 参数:list--当前在线用户链表 elem--要查看的用户元素 44 | 返回值:true or false 45 | ***************************************************/ 46 | int isOnLine(ListNode *list , User *user) 47 | { 48 | ListNode *p = list , *pre = p; 49 | while(p!=NULL && strcmp(p->user.userName , (*user).userName) != 0) 50 | { 51 | pre = p; 52 | p = p->next; 53 | }//while 54 | 55 | /*不存在该在线用户*/ 56 | if(p == NULL) 57 | return 0; 58 | return 1; 59 | } 60 | 61 | /**************************************************** 62 | 函数名:deleteNode 63 | 功能:删除在线用户链表指定节点 64 | 参数:list--当前在线用户链表 elem--要删除的元素 65 | 返回值:返回创建的链表 66 | *****************************************************/ 67 | void deleteNode(ListNode *list , User *user) 68 | { 69 | if(list == NULL) 70 | return; 71 | 72 | ListNode *p = list , *pre = p; 73 | while(p!=NULL && strcmp(p->user.userName , (*user).userName) != 0) 74 | { 75 | pre = p; 76 | p = p->next; 77 | }//while 78 | 79 | /*不存在该在线用户*/ 80 | if(p == NULL) 81 | return ; 82 | /*该用户位于链表头部*/ 83 | else if(p == list) 84 | { 85 | list = list->next; 86 | }//elif 87 | /*该用户位于链表尾部*/ 88 | else if(p->next == NULL) 89 | { 90 | pre->next = NULL; 91 | }//elif 92 | /*该用户节点位于链表中间*/ 93 | else 94 | { 95 | pre->next = p->next; 96 | }//else 97 | /*释放该用户节点占用的空间*/ 98 | free(p); 99 | p = NULL; 100 | } 101 | 102 | /**************************************************** 103 | 函数名:displayList 104 | 功能:显示在线用户链表 105 | 参数:list--当前在线用户链表 106 | 返回值:返回创建的链表 107 | *****************************************************/ 108 | void displayList(ListNode *list) 109 | { 110 | if(list == NULL) 111 | return; 112 | else 113 | { 114 | ListNode *p = list; 115 | while(p->next != NULL) 116 | { 117 | printf("%s --> ", p->user.userName); 118 | p = p->next; 119 | }//while 120 | printf("%s\n", p->user.userName); 121 | }//else 122 | } 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /select_socket/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | #define PORT 8888 17 | #define MAX_LINE 2048 18 | #define LISTENQ 20 19 | 20 | 21 | int main(int argc , char **argv) 22 | { 23 | int i, maxi, maxfd, listenfd, connfd, sockfd; 24 | 25 | int nready , client[FD_SETSIZE]; 26 | 27 | ssize_t n, ret; 28 | 29 | fd_set rset , allset; 30 | 31 | char buf[MAX_LINE]; 32 | 33 | socklen_t clilen; 34 | 35 | struct sockaddr_in servaddr , cliaddr; 36 | 37 | /*(1) 得到监听描述符*/ 38 | listenfd = socket(AF_INET , SOCK_STREAM , 0); 39 | 40 | /*(2) 绑定套接字*/ 41 | bzero(&servaddr , sizeof(servaddr)); 42 | servaddr.sin_family = AF_INET; 43 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 44 | servaddr.sin_port = htons(PORT); 45 | 46 | bind(listenfd , (struct sockaddr *)&servaddr , sizeof(servaddr)); 47 | 48 | /*(3) 监听*/ 49 | listen(listenfd , LISTENQ); 50 | 51 | /*(4) 设置select*/ 52 | maxfd = listenfd; 53 | maxi = -1; 54 | for(i=0 ; i maxfd) 100 | maxfd = connfd; 101 | if(i > maxi) 102 | maxi = i; 103 | 104 | if(--nready < 0) 105 | continue; 106 | }//if 107 | 108 | for(i=0; i<=maxi ; ++i) 109 | { 110 | if((sockfd = client[i]) < 0) 111 | continue; 112 | if(FD_ISSET(sockfd , &rset)) 113 | { 114 | /*处理客户请求*/ 115 | printf("\nreading the socket~~~ \n"); 116 | 117 | bzero(buf , MAX_LINE); 118 | if((n = read(sockfd , buf , MAX_LINE)) <= 0) 119 | { 120 | close(sockfd); 121 | FD_CLR(sockfd , &allset); 122 | client[i] = -1; 123 | }//if 124 | else{ 125 | printf("clint[%d] send message: %s\n", i , buf); 126 | if((ret = write(sockfd , buf , n)) != n) 127 | { 128 | printf("error writing to the sockfd!\n"); 129 | break; 130 | }//if 131 | }//else 132 | if(--nready <= 0) 133 | break; 134 | }//if 135 | }//for 136 | }//while 137 | } 138 | -------------------------------------------------------------------------------- /poll_socket/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include /*for OPEN_MAX*/ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | #ifndef OPEN_MAX 18 | #define OPEN_MAX 1024 19 | #endif 20 | 21 | #ifndef INFTIM 22 | #define INFTIM -1 23 | #endif 24 | 25 | #define PORT 8888 26 | #define MAX_LINE 2048 27 | #define LISTENQ 20 28 | 29 | 30 | int main(int argc , char **argv) 31 | { 32 | int i, maxi, listenfd, connfd, sockfd; 33 | 34 | int nready; 35 | 36 | ssize_t n, ret; 37 | 38 | struct pollfd client[OPEN_MAX]; 39 | 40 | char buf[MAX_LINE]; 41 | 42 | socklen_t clilen; 43 | 44 | struct sockaddr_in servaddr , cliaddr; 45 | 46 | /*(1) 得到监听描述符*/ 47 | listenfd = socket(AF_INET , SOCK_STREAM , 0); 48 | 49 | /*(2) 绑定套接字*/ 50 | bzero(&servaddr , sizeof(servaddr)); 51 | servaddr.sin_family = AF_INET; 52 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 53 | servaddr.sin_port = htons(PORT); 54 | 55 | bind(listenfd , (struct sockaddr *)&servaddr , sizeof(servaddr)); 56 | 57 | /*(3) 监听*/ 58 | listen(listenfd , LISTENQ); 59 | 60 | /*(4) 设置poll*/ 61 | client[0].fd = listenfd; 62 | client[0].events = POLLRDNORM; 63 | for(i=1 ; i maxi) 108 | maxi = i; 109 | 110 | if(--nready < 0) 111 | continue; 112 | }//if 113 | 114 | for(i=1; i<=maxi ; ++i) 115 | { 116 | if((sockfd = client[i].fd) < 0) 117 | continue; 118 | /*该链接描述符实际发生的事件*/ 119 | if(client[i].revents & (POLLRDNORM | POLLERR)) 120 | { 121 | /*处理客户请求*/ 122 | printf("\nreading the socket~~~ \n"); 123 | 124 | bzero(buf , MAX_LINE); 125 | if((n = read(sockfd , buf , MAX_LINE)) <= 0) 126 | { 127 | close(sockfd); 128 | client[i].fd = -1; 129 | }//if 130 | else{ 131 | printf("clint[%d] send message: %s\n", i , buf); 132 | if((ret = write(sockfd , buf , n)) != n) 133 | { 134 | printf("error writing to the sockfd!\n"); 135 | break; 136 | }//if 137 | }//else 138 | if(--nready <= 0) 139 | break; 140 | }//if 141 | }//for 142 | }//while 143 | exit(0); 144 | } 145 | -------------------------------------------------------------------------------- /ChatRome -- select/client/client.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 客户端程序代码server.c 3 | * 2015-12-09 yrr实现 4 | * 5 | ********************************************************************************/ 6 | 7 | #include "config.h" 8 | 9 | 10 | /********************************************* 11 | 函数名:main 12 | 功能:聊天室客户端main函数入口 13 | 参数:参数个数argc 用户链接地址argv 14 | 返回值:正常退出返回 0 否则返回 1 15 | **********************************************/ 16 | int main(int argc , char *argv[]) 17 | { 18 | int sockfd , choice , ret; //choice代表用户在主界面所做选择,ret代表操作结果 19 | struct sockaddr_in servaddr; 20 | struct hostent *host; 21 | 22 | /*声明消息变量*/ 23 | Message message; 24 | /*声明消息缓冲区*/ 25 | char buf[MAX_LINE]; 26 | 27 | /*UserInfo*/ 28 | User user; 29 | strcpy(user.userName , "***"); 30 | user.speak = 1; 31 | 32 | 33 | /*判断是否为合法输入*/ 34 | if(argc != 2) 35 | { 36 | perror("usage:tcpcli "); 37 | exit(1); 38 | }//if 39 | 40 | while(1) 41 | { 42 | /*(1) 创建套接字*/ 43 | if((sockfd = socket(AF_INET , SOCK_STREAM , 0)) == -1) 44 | { 45 | perror("socket error"); 46 | exit(1); 47 | }//if 48 | 49 | /*(2) 设置链接服务器地址结构*/ 50 | bzero(&servaddr , sizeof(servaddr)); /*清空地址结构*/ 51 | servaddr.sin_family = AF_INET; /*使用IPV4通信域*/ 52 | servaddr.sin_port = htons(PORT); /*端口号转换为网络字节序*/ 53 | //servaddr.sin_addr = *((struct in_addr *)host->h_addr); /*可接受任意地址*/ 54 | if(inet_pton(AF_INET , argv[1] , &servaddr.sin_addr) < 0) 55 | { 56 | printf("inet_pton error for %s\n",argv[1]); 57 | exit(1); 58 | }//if 59 | 60 | /*(3) 发送链接服务器请求*/ 61 | if( connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0) 62 | { 63 | perror("connect error"); 64 | exit(1); 65 | }//if 66 | 67 | /*(4) 显示聊天室主界面*/ 68 | mainInterface(); 69 | setbuf(stdin,NULL); //是linux中的C函数,主要用于打开和关闭缓冲机制 70 | scanf("%d",&choice); 71 | setbuf(stdin,NULL); 72 | while(choice != 1 && choice != 2 && choice != 3 && choice !=4) 73 | { 74 | printf("未找到命令,请重新输入!\n"); 75 | setbuf(stdin,NULL); //是linux中的C函数,主要用于打开和关闭缓冲机制 76 | scanf("%d",&choice); 77 | setbuf(stdin,NULL); 78 | }//while 79 | 80 | /*清空缓冲区*/ 81 | switch(choice) 82 | { 83 | case REGISTER: /*注册请求*/ 84 | memset(&message , 0 , sizeof(message)); 85 | memset(buf , 0 , MAX_LINE); 86 | message.msgType = REGISTER; 87 | strcpy(message.content , ""); 88 | message.sendAddr = servaddr; 89 | /*首先向服务器发送注册请求*/ 90 | memcpy(buf , &message , sizeof(message)); 91 | send(sockfd , buf , sizeof(buf) , 0); 92 | registerUser(sockfd); 93 | //goto sign; 94 | break; 95 | case LOGIN: /*登陆请求*/ 96 | memset(&message , 0 , sizeof(message)); 97 | memset(buf , 0 , MAX_LINE); 98 | message.msgType = LOGIN; 99 | strcpy(message.content , ""); 100 | message.sendAddr = servaddr; 101 | /*向服务器发送登陆请求*/ 102 | memcpy(buf , &message , sizeof(message)); 103 | send(sockfd , buf , sizeof(buf) , 0); 104 | loginUser(sockfd); 105 | break; 106 | case HELP: /*帮助请求,显示帮助界面*/ 107 | helpInterface(); 108 | //goto sign; 109 | break; 110 | case EXIT: 111 | close(sockfd); 112 | printf("退出聊天室!\n"); 113 | exit(0); /*用户退出*/ 114 | break; 115 | default: 116 | printf("unknown operation.\n"); 117 | //goto sign; 118 | break; 119 | }//switch 120 | }//while 121 | close(sockfd); 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /ChatRome -- select/server/config.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 基本配置文件 -- 包含所需头文件 3 | * 用户信息结构体定义 4 | * 在线用户链表定义 5 | ********************************************************************************/ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include /*使用memcpy所需的头文件*/ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | /*FD_SETSIZE定义描述符集的大小,定义在sys/types.h中*/ 31 | #ifndef FD_SETSIZE 32 | #define FD_SETSIZE 256 33 | #endif 34 | 35 | #define MAX_LINE 8192 36 | #define PORT 8888 37 | #define LISTENEQ 6000 38 | 39 | /*预定义数据库名称*/ 40 | #define DB_NAME "/home/yangrui/projects/Socket/ChatRome_select/chatRome.db" 41 | 42 | /*标志*/ 43 | enum Flag{ 44 | YES, /*代表被禁言*/ 45 | NO /*代表没有被禁言*/ 46 | }; 47 | 48 | /*定义服务器--客户端 消息传送类型*/ 49 | enum MessageType{ 50 | REGISTER = 1, /*注册请求*/ 51 | LOGIN, /*登陆请求*/ 52 | HELP, /*帮助请求*/ 53 | EXIT, /*退出请求*/ 54 | VIEW_USER_LIST, /*查看在线列表*/ 55 | GROUP_CHAT, /*群聊请求*/ 56 | PERSONAL_CHAT, /*私聊请求*/ 57 | VIEW_RECORDS, /*查看聊天记录请求*/ 58 | RESULT, /*结果消息类型*/ 59 | UNKONWN /*未知请求类型*/ 60 | }; 61 | 62 | /*定义操作结果 */ 63 | enum StateRet{ 64 | EXCEED, //已达服务器链接上限 65 | SUCCESS, //成功 66 | FAILED, //失败 67 | DUPLICATEID, //重复的用户名 68 | INVALID, //不合法的用户名 69 | ID_NOT_EXIST, //账号不存在 70 | WRONGPWD, //密码错误 71 | ALREADY_ONLINE, //已经在线 72 | ID_NOT_ONLINE, //账号不在线 73 | ALL_NOT_ONLINE, //无人在线 74 | MESSAGE_SELF //消息对象不能选择自己 75 | }; 76 | 77 | 78 | /*定义服务器 -- 客户端 消息传送结构体*/ 79 | typedef struct _Message{ 80 | char content[2048]; /*针对聊天类型的消息,填充该字段*/ 81 | int msgType; /*消息类型 即为MessageType中的值*/ 82 | int msgRet; /*针对操作结果类型的消息,填充该字段*/ 83 | struct sockaddr_in sendAddr; /*发送者IP*/ 84 | struct sockaddr_in recvAddr; 85 | char sendName[20]; /*发送者名称*/ 86 | char recvName[20]; /*接收者名称*/ 87 | char msgTime[20]; /*消息发送时间*/ 88 | }Message; 89 | 90 | //用户信息结构体 91 | typedef struct _User{ 92 | char userName[20]; //用户名 93 | char password[20]; 94 | struct sockaddr_in userAddr; //用户IP地址,选择IPV4 95 | int sockfd; //当前用户套接字描述符 96 | int speak; //是否禁言标志 97 | char registerTime[20]; //记录用户注册时间 98 | }User; 99 | 100 | /*定义用户链表结构体*/ 101 | typedef struct _ListNode{ 102 | User user; 103 | struct _ListNode *next; 104 | }ListNode; 105 | 106 | 107 | /*定义在线用户链表*/ 108 | extern ListNode *userList; 109 | 110 | /*server.c 客户请求处理函数*/ 111 | extern void* handleRequest(int *fd); 112 | 113 | /*config.c文件函数声明*/ 114 | extern char *stateMsg(int stateRet); 115 | extern void copyUser(User *user1 , User *user2); 116 | 117 | /*chat.c文件函数声明*/ 118 | extern void enterChat(int *fd); 119 | extern int groupChat(Message *msg , int sockfd); 120 | extern int personalChat(Message *msg , int sockfd); 121 | extern int viewUserList(Message *msg , int sockfd); 122 | extern int viewRecords(Message *msg , int sockfd); 123 | 124 | /*list.c文件函数声明*/ 125 | extern ListNode* insertNode(ListNode *list , User *user); 126 | extern int isOnLine(ListNode *list , User *user); 127 | extern void deleteNode(ListNode *list , User *user); 128 | extern void displayList(ListNode *list); 129 | 130 | /*login.c文件函数声明*/ 131 | extern int loginUser(Message *msg , int sockfd); 132 | 133 | /*register.c文件函数声明*/ 134 | extern int registerUser(Message *msg , int sockfd); 135 | -------------------------------------------------------------------------------- /select_socket/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define PORT 8888 16 | #define MAX_LINE 2048 17 | 18 | int max(int a , int b) 19 | { 20 | return a > b ? a : b; 21 | } 22 | 23 | /*readline函数实现*/ 24 | ssize_t readline(int fd, char *vptr, size_t maxlen) 25 | { 26 | ssize_t n, rc; 27 | char c, *ptr; 28 | 29 | ptr = vptr; 30 | for (n = 1; n < maxlen; n++) { 31 | if ( (rc = read(fd, &c,1)) == 1) { 32 | *ptr++ = c; 33 | if (c == '\n') 34 | break; /* newline is stored, like fgets() */ 35 | } else if (rc == 0) { 36 | *ptr = 0; 37 | return(n - 1); /* EOF, n - 1 bytes were read */ 38 | } else 39 | return(-1); /* error, errno set by read() */ 40 | } 41 | 42 | *ptr = 0; /* null terminate like fgets() */ 43 | return(n); 44 | } 45 | 46 | /*普通客户端消息处理函数*/ 47 | void str_cli(int sockfd) 48 | { 49 | /*发送和接收缓冲区*/ 50 | char sendline[MAX_LINE] , recvline[MAX_LINE]; 51 | while(fgets(sendline , MAX_LINE , stdin) != NULL) 52 | { 53 | write(sockfd , sendline , strlen(sendline)); 54 | 55 | bzero(recvline , MAX_LINE); 56 | if(readline(sockfd , recvline , MAX_LINE) == 0) 57 | { 58 | perror("server terminated prematurely"); 59 | exit(1); 60 | }//if 61 | 62 | if(fputs(recvline , stdout) == EOF) 63 | { 64 | perror("fputs error"); 65 | exit(1); 66 | }//if 67 | 68 | bzero(sendline , MAX_LINE); 69 | }//while 70 | } 71 | 72 | /*采用select的客户端消息处理函数*/ 73 | void str_cli2(FILE* fp , int sockfd) 74 | { 75 | int maxfd; 76 | fd_set rset; 77 | /*发送和接收缓冲区*/ 78 | char sendline[MAX_LINE] , recvline[MAX_LINE]; 79 | 80 | FD_ZERO(&rset); 81 | while(1) 82 | { 83 | /*将文件描述符和套接字描述符添加到rset描述符集*/ 84 | FD_SET(fileno(fp) , &rset); 85 | FD_SET(sockfd , &rset); 86 | maxfd = max(fileno(fp) , sockfd) + 1; 87 | select(maxfd , &rset , NULL , NULL , NULL); 88 | 89 | if(FD_ISSET(fileno(fp) , &rset)) 90 | { 91 | if(fgets(sendline , MAX_LINE , fp) == NULL) 92 | { 93 | printf("read nothing~\n"); 94 | close(sockfd); /*all done*/ 95 | return ; 96 | }//if 97 | sendline[strlen(sendline) - 1] = '\0'; 98 | write(sockfd , sendline , strlen(sendline)); 99 | }//if 100 | 101 | if(FD_ISSET(sockfd , &rset)) 102 | { 103 | if(readline(sockfd , recvline , MAX_LINE) == 0) 104 | { 105 | 106 | perror("handleMsg: server terminated prematurely.\n"); 107 | exit(1); 108 | }//if 109 | 110 | if(fputs(recvline , stdout) == EOF) 111 | { 112 | perror("fputs error"); 113 | exit(1); 114 | }//if 115 | }//if 116 | }//while 117 | } 118 | 119 | int main(int argc , char **argv) 120 | { 121 | /*声明套接字和链接服务器地址*/ 122 | int sockfd; 123 | struct sockaddr_in servaddr; 124 | 125 | /*判断是否为合法输入*/ 126 | if(argc != 2) 127 | { 128 | perror("usage:tcpcli "); 129 | exit(1); 130 | }//if 131 | 132 | /*(1) 创建套接字*/ 133 | if((sockfd = socket(AF_INET , SOCK_STREAM , 0)) == -1) 134 | { 135 | perror("socket error"); 136 | exit(1); 137 | }//if 138 | 139 | /*(2) 设置链接服务器地址结构*/ 140 | bzero(&servaddr , sizeof(servaddr)); 141 | servaddr.sin_family = AF_INET; 142 | servaddr.sin_port = htons(PORT); 143 | if(inet_pton(AF_INET , argv[1] , &servaddr.sin_addr) < 0) 144 | { 145 | printf("inet_pton error for %s\n",argv[1]); 146 | exit(1); 147 | }//if 148 | 149 | /*(3) 发送链接服务器请求*/ 150 | if(connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0) 151 | { 152 | perror("connect error"); 153 | exit(1); 154 | }//if 155 | 156 | /*调用普通消息处理函数*/ 157 | str_cli(sockfd); 158 | /*调用采用select技术的消息处理函数*/ 159 | //str_cli2(stdin , sockfd); 160 | exit(0); 161 | } 162 | -------------------------------------------------------------------------------- /epoll_socket/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | #ifndef CONNECT_SIZE 17 | #define CONNECT_SIZE 256 18 | #endif 19 | 20 | #define PORT 7777 21 | #define MAX_LINE 2048 22 | #define LISTENQ 20 23 | 24 | void setNonblocking(int sockfd) 25 | { 26 | int opts; 27 | opts=fcntl(sockfd,F_GETFL); 28 | if(opts<0) 29 | { 30 | perror("fcntl(sock,GETFL)"); 31 | return; 32 | }//if 33 | 34 | opts = opts|O_NONBLOCK; 35 | if(fcntl(sockfd,F_SETFL,opts)<0) 36 | { 37 | perror("fcntl(sock,SETFL,opts)"); 38 | return; 39 | }//if 40 | } 41 | 42 | int main(int argc , char **argv) 43 | { 44 | int i, listenfd, connfd, sockfd, epfd, nfds; 45 | 46 | ssize_t n, ret; 47 | 48 | char buf[MAX_LINE]; 49 | 50 | socklen_t clilen; 51 | 52 | struct sockaddr_in servaddr , cliaddr; 53 | 54 | /*声明epoll_event结构体变量,ev用于注册事件,数组用于回传要处理的事件*/ 55 | struct epoll_event ev, events[20]; 56 | 57 | /*(1) 得到监听描述符*/ 58 | listenfd = socket(AF_INET , SOCK_STREAM , 0); 59 | setNonblocking(listenfd); 60 | 61 | /*生成用于处理accept的epoll专用文件描述符*/ 62 | epfd = epoll_create(CONNECT_SIZE); 63 | /*设置监听描述符*/ 64 | ev.data.fd = listenfd; 65 | /*设置处理事件类型*/ 66 | ev.events = EPOLLIN | EPOLLET; 67 | /*注册事件*/ 68 | epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev); 69 | 70 | /*(2) 绑定套接字*/ 71 | bzero(&servaddr , sizeof(servaddr)); 72 | servaddr.sin_family = AF_INET; 73 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 74 | servaddr.sin_port = htons(PORT); 75 | 76 | bind(listenfd , (struct sockaddr *)&servaddr , sizeof(servaddr)); 77 | 78 | /*(3) 监听*/ 79 | listen(listenfd , LISTENQ); 80 | 81 | /*(4) 进入服务器接收请求死循环*/ 82 | while(1) 83 | { 84 | /*等待事件发生*/ 85 | nfds = epoll_wait(epfd , events , CONNECT_SIZE , -1); 86 | if(nfds <= 0) 87 | continue; 88 | 89 | printf("nfds = %d\n" , nfds); 90 | /*处理发生的事件*/ 91 | for(i=0 ; i0接收到的字节数*/ 32 | if(nRead <= 0) 33 | { 34 | printf("您已经异常掉线,请重新登录!\n"); 35 | close(connfd); 36 | exit(0); 37 | }//if 38 | 39 | memset(&message , 0 , sizeof(message)); 40 | memcpy(&message , buf , sizeof(buf)); 41 | 42 | switch(message.msgType) 43 | { 44 | case VIEW_USER_LIST: 45 | printf("当前在线用户有:\n %s\n", message.content); 46 | break; 47 | case PERSONAL_CHAT: 48 | sprintf(str , "%s \t %s \t对你说: %s\n", message.sendName , message.msgTime , message.content); 49 | printf("\n%s\n", str); 50 | break; 51 | case GROUP_CHAT: 52 | sprintf(str , "%s \t %s \t发送群消息: %s\n", message.sendName , message.msgTime , message.content); 53 | printf("\n%s\n", str); 54 | break; 55 | case VIEW_RECORDS: 56 | if(strcmp(message.recvName , "") == 0) 57 | printf("你参与的群消息记录:\n\n"); 58 | else 59 | printf("你和%s的聊天记录:\n\n", message.recvName); 60 | printf("%s\n" , message.content); 61 | break; 62 | case RESULT: 63 | printf("你的操作结果:%s\n", message.content); 64 | default: 65 | break; 66 | }//switch 67 | }//while 68 | } 69 | 70 | /*********************************************** 71 | 函数名:enterChat 72 | 功能:用户登陆成功后进入聊天模式 73 | 参数:user--当前用户 , sockfd -- 套接字描述符 74 | 返回值:正常退出返回 0 , 否则返回 1 75 | *************************************************/ 76 | void enterChat(User *user , int sockfd) 77 | { 78 | int choice , ret; 79 | char c , buf[MAX_LINE] , str[MAX_LINE]; 80 | Message message; /*消息对象*/ 81 | time_t timep; /*存储当前时间*/ 82 | 83 | pthread_t pid; /*处理接收消息线程*/ 84 | 85 | /*创建接收消息线程*/ 86 | ret = pthread_create(&pid , NULL , (void *)recvMsg , (void *)&sockfd); 87 | if(ret != 0) 88 | { 89 | printf("软件异常,请重新登录!\n"); 90 | memset(&message , 0 , sizeof(message)); 91 | strcpy(message.sendName , (*user).userName); 92 | message.msgType = EXIT; 93 | send(sockfd , buf , sizeof(buf) , 0); 94 | close(sockfd); 95 | exit(1); 96 | } 97 | /*清空标准输入缓冲区*/ 98 | setbuf(stdin, NULL); 99 | 100 | /*进入处理用户发送消息缓冲区*/ 101 | while(1) 102 | { 103 | memset(&message , 0 , sizeof(message)); 104 | strcpy(message.sendName , (*user).userName); 105 | memset(&str , 0 , MAX_LINE); 106 | memset(buf , 0 , MAX_LINE); 107 | /*usleep函数将该进程挂起一定时间,单位微秒,头文件unistd.h*/ 108 | usleep(100000); 109 | 110 | /*进入聊天主界面*/ 111 | chatInterface((*user).userName); 112 | setbuf(stdin,NULL); //是linux中的C函数,主要用于打开和关闭缓冲机制 113 | scanf("%d",&choice); 114 | while(choice != 1 && choice != 2 && choice != 3 && choice !=4 && choice != 5) 115 | { 116 | printf("未知操作,请重新输入!\n"); 117 | setbuf(stdin,NULL); //是linux中的C函数,主要用于打开和关闭缓冲机制 118 | scanf("%d",&choice); 119 | setbuf(stdin,NULL); 120 | }//while 121 | 122 | switch(choice) 123 | { 124 | case 1: /*查看当前在线用户列表*/ 125 | message.msgType = VIEW_USER_LIST; 126 | memcpy(buf , &message , sizeof(message)); 127 | send(sockfd , buf , sizeof(buf) , 0); 128 | break; 129 | case 2: /*私聊*/ 130 | message.msgType = PERSONAL_CHAT; 131 | printf("请输入聊天对象:\n"); 132 | setbuf(stdin , NULL); 133 | scanf("%s" , str); 134 | strcpy(message.recvName , str); 135 | 136 | printf("请输入聊天内容:\n"); 137 | setbuf(stdin , NULL); 138 | fgets(message.content , MAX_LINE , stdin); 139 | (message.content)[strlen(message.content) - 1] = '\0'; 140 | 141 | /*获得当前时间*/ 142 | time(&timep); 143 | strcpy(message.msgTime , ctime(&timep)); 144 | memcpy(buf , &message , sizeof(message)); 145 | send(sockfd , buf , sizeof(buf) , 0); 146 | break; 147 | case 3: /*群聊*/ 148 | message.msgType = GROUP_CHAT; 149 | strcpy(message.recvName , ""); 150 | 151 | printf("请输入聊天内容:\n"); 152 | setbuf(stdin , NULL); 153 | fgets(message.content , MAX_LINE , stdin); 154 | (message.content)[strlen(message.content) - 1] = '\0'; 155 | 156 | /*获得当前时间*/ 157 | time(&timep); 158 | strcpy(message.msgTime , ctime(&timep)); 159 | memcpy(buf , &message , sizeof(message)); 160 | send(sockfd , buf , sizeof(buf) , 0); 161 | break; 162 | case 4: /*查看聊天记录*/ 163 | message.msgType = VIEW_RECORDS; 164 | printf("请输入查看的聊天对象:\n"); 165 | setbuf(stdin , NULL); 166 | scanf("%s" , str); 167 | strcpy(message.recvName , str); 168 | memcpy(buf , &message , sizeof(message)); 169 | send(sockfd , buf , sizeof(buf) , 0); 170 | break; 171 | case 5: /*退出登陆*/ 172 | message.msgType = EXIT; 173 | memcpy(buf , &message , sizeof(message)); 174 | send(sockfd , buf , sizeof(buf) , 0); 175 | close(sockfd); 176 | exit(0); 177 | default: /*未知操作类型*/ 178 | break; 179 | }//switch 180 | }//while 181 | //close(sockfd); 182 | } 183 | 184 | 185 | -------------------------------------------------------------------------------- /ChatRome -- select/server/server.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 服务器端程序代码server.c 3 | * 2015-12-09 yrr实现 4 | * 5 | ********************************************************************************/ 6 | 7 | #include "config.h" 8 | 9 | /*定义全局变量 -- 在线用户链表*/ 10 | ListNode *userList = NULL; 11 | 12 | /********************************************* 13 | 函数名:main 14 | 功能:聊天室服务器main函数入口 15 | 参数:无 16 | 返回值:正常退出返回 0 否则返回 1 17 | **********************************************/ 18 | int main(void) 19 | { 20 | /*声明服务器监听描述符和客户链接描述符*/ 21 | int i , n , ret , maxi , maxfd , listenfd , connfd , sockfd; 22 | 23 | socklen_t clilen; 24 | 25 | pthread_t pid; 26 | 27 | /*套接字选项*/ 28 | int opt = 1; 29 | 30 | /*声明服务器地址和客户地址结构*/ 31 | struct sockaddr_in servaddr , cliaddr; 32 | 33 | /*声明描述符集*/ 34 | fd_set rset , allset; 35 | //nready为当前可用的描述符数量 36 | int nready , client_sockfd[FD_SETSIZE]; 37 | 38 | /*声明消息变量*/ 39 | Message message; 40 | /*声明消息缓冲区*/ 41 | char buf[MAX_LINE]; 42 | 43 | /*UserInfo*/ 44 | User user; 45 | 46 | /*(1) 创建套接字*/ 47 | if((listenfd = socket(AF_INET , SOCK_STREAM , 0)) == -1) 48 | { 49 | perror("socket error.\n"); 50 | exit(1); 51 | }//if 52 | 53 | /*(2) 初始化地址结构*/ 54 | bzero(&servaddr , sizeof(servaddr)); 55 | servaddr.sin_family = AF_INET; 56 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 57 | servaddr.sin_port = htons(PORT); 58 | 59 | /*(3) 绑定套接字和端口*/ 60 | setsockopt(listenfd , SOL_SOCKET , SO_REUSEADDR , &opt , sizeof(opt)); 61 | 62 | if(bind(listenfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0) 63 | { 64 | perror("bind error.\n"); 65 | exit(1); 66 | }//if 67 | 68 | /*(4) 监听*/ 69 | if(listen(listenfd , LISTENEQ) < 0) 70 | { 71 | perror("listen error.\n"); 72 | exit(1); 73 | }//if 74 | 75 | /*(5) 首先初始化客户端描述符集*/ 76 | maxfd = listenfd; 77 | maxi = -1; 78 | for(i=0; i maxfd) 130 | maxfd = connfd; 131 | 132 | /*max index in client_sockfd[]*/ 133 | if(i > maxi) 134 | maxi = i; 135 | 136 | /*no more readable descriptors*/ 137 | if(--nready <= 0) 138 | continue; 139 | }//if 140 | /*接下来逐个处理连接描述符*/ 141 | for(i=0 ; i<=maxi ; ++i) 142 | { 143 | if((sockfd = client_sockfd[i]) < 0) 144 | continue; 145 | 146 | if(FD_ISSET(sockfd , &rset)) 147 | { 148 | /*如果当前没有可以读的套接字,退出循环*/ 149 | if(--nready < 0) 150 | break; 151 | pthread_create(&pid , NULL , (void *)handleRequest , (void *)&sockfd); 152 | 153 | }//if 154 | /*清除处理完的链接描述符*/ 155 | FD_CLR(sockfd , &allset); 156 | client_sockfd[i] = -1; 157 | }//for 158 | }//while 159 | 160 | close(listenfd); 161 | return 0; 162 | } 163 | 164 | /*处理客户请求的线程*/ 165 | void* handleRequest(int *fd) 166 | { 167 | int sockfd , ret , n; 168 | /*声明消息变量*/ 169 | Message message; 170 | /*声明消息缓冲区*/ 171 | char buf[MAX_LINE]; 172 | 173 | sockfd = *fd; 174 | 175 | memset(buf , 0 , MAX_LINE); 176 | memset(&message , 0 , sizeof(message)); 177 | 178 | //接收用户发送的消息 179 | n = recv(sockfd , buf , sizeof(buf)+1 , 0); 180 | if(n <= 0) 181 | { 182 | //关闭当前描述符,并清空描述符数组 183 | fflush(stdout); 184 | close(sockfd); 185 | *fd = -1; 186 | printf("来自%s的退出请求!\n", inet_ntoa(message.sendAddr.sin_addr)); 187 | return NULL; 188 | }//if 189 | else{ 190 | memcpy(&message , buf , sizeof(buf)); 191 | /*为每个客户操作链接创建一个线程*/ 192 | switch(message.msgType) 193 | { 194 | case REGISTER: 195 | { 196 | printf("来自%s的注册请求!\n", inet_ntoa(message.sendAddr.sin_addr)); 197 | ret = registerUser(&message , sockfd); 198 | memset(&message , 0 , sizeof(message)); 199 | message.msgType = RESULT; 200 | message.msgRet = ret; 201 | strcpy(message.content , stateMsg(ret)); 202 | memset(buf , 0 , MAX_LINE); 203 | memcpy(buf , &message , sizeof(message)); 204 | /*发送操作结果消息*/ 205 | send(sockfd , buf , sizeof(buf) , 0); 206 | printf("注册:%s\n", stateMsg(ret)); 207 | close(sockfd); 208 | *fd = -1; 209 | return NULL; 210 | break; 211 | }//case 212 | case LOGIN: 213 | { 214 | printf("来自%s的登陆请求!\n", inet_ntoa(message.sendAddr.sin_addr)); 215 | ret = loginUser(&message , sockfd); 216 | memset(&message , 0 , sizeof(message)); 217 | message.msgType = RESULT; 218 | message.msgRet = ret; 219 | strcpy(message.content , stateMsg(ret)); 220 | memset(buf , 0 , MAX_LINE); 221 | memcpy(buf , &message , sizeof(message)); 222 | /*发送操作结果消息*/ 223 | send(sockfd , buf , sizeof(buf) , 0); 224 | printf("登录:%s\n", stateMsg(ret)); 225 | /*进入服务器处理聊天界面*/ 226 | enterChat(&sockfd); 227 | break; 228 | }//case 229 | default: 230 | printf("unknown operation.\n"); 231 | break; 232 | }//switch 233 | }//else 234 | 235 | close(sockfd); 236 | *fd = -1; 237 | return NULL; 238 | } 239 | -------------------------------------------------------------------------------- /ChatRome -- select/server/chat.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 服务器处理用户聊天操作实现文件 3 | * 2015-12-16 yrr实现 4 | * 5 | ********************************************************************************/ 6 | 7 | #include "config.h" 8 | 9 | extern ListNode *userList; 10 | 11 | /************************************************** 12 | 函数名:groupChat 13 | 功能:群聊函数实现 14 | 参数:msg--用户发送的群聊消息 sockfd -- 发送者套接字 15 | 返回值:成功登陆返回SUCCESS 否则返回异常类型 16 | ****************************************************/ 17 | int groupChat(Message *msg , int sockfd) 18 | { 19 | ListNode *p; 20 | 21 | int ret; 22 | 23 | /*声明数据库变量*/ 24 | sqlite3 *db; 25 | sqlite3_stmt *stmt; 26 | const char *tail; 27 | /*声明sql语句存储变量*/ 28 | char sql[128]; 29 | 30 | /*消息发送缓冲区*/ 31 | char buf[MAX_LINE]; 32 | /*消息内容*/ 33 | Message message; 34 | memset(&message , 0 , sizeof(message)); 35 | strcpy(message.sendName , (*msg).sendName); 36 | strcpy(message.recvName , (*msg).recvName); 37 | message.msgType = (*msg).msgType; 38 | 39 | /*查看在线用户*/ 40 | p = userList; 41 | /*除了自己无人在线*/ 42 | if(p->next == NULL) 43 | { 44 | /*改变消息类型为RESULT*/ 45 | message.msgType = RESULT; 46 | strcpy(message.content, stateMsg(ALL_NOT_ONLINE)); 47 | memset(buf , 0 , MAX_LINE); 48 | memcpy(buf , &message , sizeof(message)); 49 | send(sockfd , buf , sizeof(buf) , 0); 50 | return ALL_NOT_ONLINE; 51 | }//if 52 | /*向所有在线用户发送消息*/ 53 | else 54 | { 55 | strcpy(message.recvName , ""); 56 | strcpy(message.content , (*msg).content); 57 | strcpy(message.msgTime , (*msg).msgTime); 58 | while(p!=NULL) 59 | { 60 | if(strcmp((p->user).userName , message.sendName) != 0) 61 | { 62 | memset(buf , 0 , MAX_LINE); 63 | memcpy(buf , &message , sizeof(message)); 64 | send((p->user).sockfd , buf , sizeof(buf) , 0); 65 | }//else 66 | p = p->next; 67 | }//while 68 | /*(1)打开数据库*/ 69 | ret = sqlite3_open(DB_NAME, &db); 70 | if(ret != SQLITE_OK) 71 | { 72 | printf("unable open database!\n"); 73 | return FAILED; 74 | }//if 75 | /*(2)执行插入操作*/ 76 | memset(sql , 0 , sizeof(sql)); 77 | sprintf(sql , "insert into Message(msgType , sendName , recvName , content , msgTime)\ 78 | values(%d,'%s','%s','%s', '%s');",message.msgType , message.sendName , 79 | message.recvName,message.content , message.msgTime); 80 | 81 | ret = sqlite3_prepare(db , sql , strlen(sql) , &stmt , &tail); 82 | if(ret != SQLITE_OK) 83 | { 84 | ret = sqlite3_step(stmt); 85 | sqlite3_finalize(stmt); 86 | sqlite3_close(db); 87 | return FAILED; 88 | }//if 89 | 90 | /*(3)顺利插入*/ 91 | ret = sqlite3_step(stmt); 92 | sqlite3_finalize(stmt); 93 | sqlite3_close(db); 94 | /*群聊处理成功*/ 95 | return SUCCESS; 96 | }//else 97 | } 98 | 99 | /************************************************** 100 | 函数名:personalChat 101 | 功能:私聊函数实现 102 | 参数:msg--用户发送的群聊消息 sockfd -- 发送者套接字 103 | 返回值:成功登陆返回SUCCESS 否则返回异常类型 104 | ****************************************************/ 105 | int personalChat(Message *msg , int sockfd) 106 | { 107 | ListNode *p; 108 | 109 | int ret; 110 | 111 | /*声明数据库变量*/ 112 | sqlite3 *db; 113 | sqlite3_stmt *stmt; 114 | const char *tail; 115 | /*声明sql语句存储变量*/ 116 | char sql[128]; 117 | 118 | /*消息发送缓冲区*/ 119 | char buf[MAX_LINE]; 120 | /*消息内容*/ 121 | Message message; 122 | memset(&message , 0 , sizeof(message)); 123 | strcpy(message.sendName , (*msg).sendName); 124 | strcpy(message.recvName , (*msg).recvName); 125 | message.msgType = (*msg).msgType; 126 | /*消息发送对象和接收对象相同*/ 127 | if(strcmp((*msg).sendName , (*msg).recvName) == 0) 128 | { 129 | printf("消息不能发送到自己!\n"); 130 | /*改变消息类型为RESULT*/ 131 | message.msgType = RESULT; 132 | strcpy(message.content, stateMsg(MESSAGE_SELF)); 133 | memset(buf , 0 , MAX_LINE); 134 | memcpy(buf , &message , sizeof(message)); 135 | send(sockfd , buf , sizeof(buf) , 0); 136 | return MESSAGE_SELF; 137 | }//if 138 | 139 | /*查找接收信息用户*/ 140 | p = userList; 141 | while(p != NULL && strcmp((p->user).userName , (*msg).recvName) != 0) 142 | { 143 | p = p->next; 144 | }//while 145 | 146 | if(p == NULL) 147 | { 148 | printf("该用户不在线!\n"); 149 | /*改变消息类型为RESULT*/ 150 | message.msgType = RESULT; 151 | strcpy(message.content, stateMsg(ID_NOT_ONLINE)); 152 | memset(buf , 0 , MAX_LINE); 153 | memcpy(buf , &message , sizeof(message)); 154 | send(sockfd , buf , sizeof(buf) , 0); 155 | return ID_NOT_ONLINE; 156 | }//if 157 | else{ 158 | strcpy(message.content , (*msg).content); 159 | strcpy(message.msgTime , (*msg).msgTime); 160 | memset(buf , 0 , MAX_LINE); 161 | memcpy(buf , &message , sizeof(message)); 162 | send((p->user).sockfd , buf , sizeof(buf) , 0); 163 | 164 | /*写到数据库*/ 165 | /*(1)打开数据库*/ 166 | ret = sqlite3_open(DB_NAME, &db); 167 | if(ret != SQLITE_OK) 168 | { 169 | printf("unable open database!\n"); 170 | return FAILED; 171 | }//if 172 | /*(2)执行插入操作*/ 173 | memset(sql , 0 , sizeof(sql)); 174 | sprintf(sql , "insert into Message(msgType , sendName , recvName , content , msgTime)\ 175 | values(%d,'%s','%s','%s', '%s');",message.msgType , message.sendName , 176 | message.recvName,message.content , message.msgTime); 177 | printf("%s\n" , sql); 178 | 179 | ret = sqlite3_prepare(db , sql , strlen(sql) , &stmt , &tail); 180 | if(ret != SQLITE_OK) 181 | { 182 | ret = sqlite3_step(stmt); 183 | sqlite3_finalize(stmt); 184 | sqlite3_close(db); 185 | return FAILED; 186 | }//if 187 | 188 | /*(3)顺利插入*/ 189 | ret = sqlite3_step(stmt); 190 | sqlite3_finalize(stmt); 191 | sqlite3_close(db); 192 | /*私聊处理成功*/ 193 | return SUCCESS; 194 | }//else 195 | } 196 | 197 | /************************************************** 198 | 函数名:viewUserList 199 | 功能:查看在线用户列表函数实现 200 | 参数:msg--用户发送的群聊消息 sockfd -- 发送者套接字 201 | 返回值:成功登陆返回SUCCESS 否则返回异常类型 202 | ****************************************************/ 203 | int viewUserList(Message *msg , int sockfd) 204 | { 205 | ListNode *p; 206 | int ret; 207 | 208 | /*消息发送缓冲区*/ 209 | char buf[MAX_LINE]; 210 | /*消息内容*/ 211 | Message message; 212 | memset(&message , 0 , sizeof(message)); 213 | strcpy(message.sendName , (*msg).sendName); 214 | strcpy(message.recvName , (*msg).recvName); 215 | message.msgType = (*msg).msgType; 216 | 217 | /*查看在线用户*/ 218 | p = userList; 219 | if(p == NULL) 220 | { 221 | /*改变消息类型为RESULT*/ 222 | message.msgType = RESULT; 223 | strcpy(message.content, stateMsg(ALL_NOT_ONLINE)); 224 | memset(buf , 0 , MAX_LINE); 225 | memcpy(buf , &message , sizeof(message)); 226 | send(sockfd , buf , sizeof(buf) , 0); 227 | return ALL_NOT_ONLINE; 228 | }//if 229 | else{ 230 | /*否则消息类型不变*/ 231 | strcpy(message.content , ""); 232 | while(p!=NULL) 233 | { 234 | strcat(message.content , "\t"); 235 | strcat(message.content , (p->user).userName); 236 | 237 | p = p->next; 238 | }//while 239 | memset(buf , 0 , MAX_LINE); 240 | memcpy(buf , &message , sizeof(message)); 241 | send(sockfd , buf , sizeof(buf) , 0); 242 | printf("查看在线列表结果:%s\n", message.content); 243 | } 244 | return SUCCESS; 245 | } 246 | 247 | /************************************************** 248 | 函数名:viewUserList 249 | 功能:查看聊天记录 250 | 参数:msg--用户发送的群聊消息 sockfd -- 发送者套接字 251 | 返回值:成功登陆返回SUCCESS 否则返回异常类型 252 | ****************************************************/ 253 | int viewRecords(Message *msg , int sockfd) 254 | { 255 | int ret; 256 | 257 | char buf[MAX_LINE] , record[MAX_LINE]; 258 | 259 | /*声明数据库变量*/ 260 | sqlite3 *db; 261 | char *errmsg = NULL; 262 | char **dbRet; 263 | int nRow , nCol , i , j , idx; 264 | 265 | /*声明sql语句存储变量*/ 266 | char sql[128]; 267 | 268 | /*存储操作结果消息*/ 269 | Message message; 270 | memset(&message , 0 , sizeof(message)); 271 | strcpy(message.sendName , (*msg).sendName); 272 | /*判断是否接收群消息*/ 273 | if(strcmp( (*msg).recvName , "all") == 0) 274 | strcpy(message.recvName , ""); 275 | else 276 | strcpy(message.recvName , (*msg).recvName); 277 | message.msgType = (*msg).msgType; 278 | 279 | /*(1)打开数据库*/ 280 | ret = sqlite3_open(DB_NAME, &db); 281 | if(ret != SQLITE_OK) 282 | { 283 | printf("unable open database.\n"); 284 | /*改变消息类型为RESULT*/ 285 | message.msgType = RESULT; 286 | strcpy(message.content, stateMsg(FAILED)); 287 | memset(buf , 0 , MAX_LINE); 288 | memcpy(buf , &message , sizeof(message)); 289 | send(sockfd , buf , sizeof(buf) , 0); 290 | 291 | return FAILED; 292 | }//if 293 | 294 | /*(2)读出两者的聊天记录,以二进制方式*/ 295 | memset(sql , 0 , sizeof(sql)); 296 | if(strcmp(message.recvName , "") == 0) 297 | sprintf(sql , "select * from Message where recvName='%s' order by msgTime;",message.recvName); 298 | else 299 | sprintf(sql , "select * from Message where sendName='%s' and recvName='%s' or sendName='%s' and recvName='%s' order by msgTime;",message.sendName , message.recvName , message.recvName , message.sendName); 300 | 301 | 302 | ret = sqlite3_get_table(db , sql , &dbRet , &nRow , &nCol , &errmsg); 303 | /*查询不成功*/ 304 | if(ret != SQLITE_OK) 305 | { 306 | sqlite3_close(db); 307 | printf("database select fail!\n"); 308 | /*改变消息类型为RESULT*/ 309 | message.msgType = RESULT; 310 | strcpy(message.content, stateMsg(FAILED)); 311 | memset(buf , 0 , MAX_LINE); 312 | memcpy(buf , &message , sizeof(message)); 313 | send(sockfd , buf , sizeof(buf) , 0); 314 | return FAILED; 315 | }//if 316 | 317 | /*查询成功,dbRet 前面第一行数据是字段名称,从 nColumn 索引开始才是真正的数据*/ 318 | idx = nCol; 319 | for(i=0; i