聊天室项目
1、簡述:
采用了cs結構
服務器端四步走:socket,bind,listen,accept
客戶端兩步走:socket,connect
簡單模型:客戶端a消息發(fā)送到服務器;服務器找到客戶端b的socket,在把消息發(fā)送給客戶端b;
設計數據庫操作存儲的一些操作比較簡單這里不提
2、看代碼:
(1)、服務器端代碼
(2)、客戶端代碼
這里寫代碼片#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <sqlite3.h> #define PORT 9999 void enter( int );char myName[20]; char Sex[20];struct Msg {char information[1024]; //發(fā)送消息;char msg[1024]; // (姓名)消息內容int id;char sex[20];int age;int password;char toname[20]; //消息發(fā)給誰char fromname[20]; //消息從誰的那邊發(fā)出來int cmd; // 消息類型char online_name[20]; //在線姓名; };// 主界面; void interface() {printf ("\t\t 1、注冊\n");printf ("\t\t 2、登錄\n");}void interface3() {//printf ("\t\t 1、注冊\n");printf ("\t\t 2、登錄\n");}//登錄后的界面; void interface2() {printf ("\t\t 1、發(fā)送文件\n");printf ("\t\t 2、群聊\n");printf ("\t\t 3、私聊\n");printf ("\t\t 4、注銷當前用戶\n");printf ("\t\t 5、顯示好友列表\n");printf ("\t\t 6、查看本地聊天記錄\n"); }//讀寫分離的讀線程的回調函數;void * readMsg(void *v){int socketfd = (int)v;struct Msg msg;while (1){read(socketfd, &msg, sizeof(msg));//printf("test msg.cmd %d,%d\n",msg.cmd,sizeof(msg));switch (msg.cmd){case -5: //私聊用戶不存在;printf("你想私聊的用戶不存在\n");break;case 10: //用戶存在并且在線;printf("用戶存在并且在線\n");break;case -6: //用戶不在線;printf("用戶存在但是不在線\n");break;case 2: // 群聊printf ("收到一條消息: %s\n", msg.information);break;case 3: // 私聊printf ("%s 給你發(fā)一條消息:%s\n", msg.fromname, msg.information);break;case 4: // 顯示在線好友列表;printf("在線的好友有:%s\n",msg.online_name);printf("3333333\n");break;case 6: //用戶注銷;printf("注銷成功!\n");return;break;}}}//注冊函數 int reg(int socketfd) {struct Msg msg;//msg.cmd = 1;while(1){msg.cmd = 1;//memset(&msg,0,sizeof(msg));//清零printf ("請輸入用戶名:\n");scanf("%s",&(msg.msg));printf ("請輸入用戶的密碼 :\n");scanf("%d",&(msg.password));write (socketfd, &msg, sizeof(msg));//來自服務器端的回復:到底有沒有注冊成功,成功了返回一個標號,要是失敗了,那么為什么失敗,返回另外一個標號,最后失敗的需要全部重新注冊read (socketfd, &msg, sizeof(msg));if (msg.cmd == 1001){printf ("你已注冊成功,歡迎加入聊天室\n");/* int a;while (1){printf("\n");interface3();printf("\n");printf("\n");sleep(1);printf("\t\t*_*輸入功能:\n");scanf("%d",&a);printf("\n");while(getchar()!= '\n');switch(a){case 2: //登錄;enter(socketfd);break;}system("clear");}*/break;}//用戶已經被注冊過了,重新注冊if (msg.cmd == -2){printf ("該用戶名已經被注冊,請重新進行注冊\n");memset(&msg,0,sizeof(msg));//清零continue;}//聊天室的登錄人數上限已經到達注冊失敗;else if(msg.cmd == -1){printf ("聊天室的上限已經到達,請重新進行注冊\n");continue;}}sleep(1);}//群聊函數, void chat(int socketfd) {struct Msg msg;msg.cmd = 2;printf ("請輸入要發(fā)送的內容: \n");//fgets(msg.information, 1024, stdin);scanf("%s",msg.information);write (socketfd, &msg, sizeof(msg)); }//私聊; void chat2(int socketfd) {struct Msg msg;msg.cmd = 3;printf ("請輸入要發(fā)送的對象名稱: \n");//fgets(msg.toname, 20, stdin);scanf("%s",msg.toname);printf ("請輸入要發(fā)送的內容: \n");//fgets(msg.information, 1024, stdin);scanf("%s",msg.information);printf("輸入自己的名字 : \n");//fgets(msg.fromname, 20, stdin);scanf("%s",msg.fromname);write (socketfd, &msg, sizeof(msg));//調用存儲聊天記錄的函數;int ret = insert_msg( &msg );if(ret == 1){printf("成功保存本地記錄\n");} }//注銷用戶; void logout(int socketfd) {char ch[2];printf("是否注銷此用戶: y/n \n");scanf("%c",ch);if(ch[0] == 'y'){struct Msg msg;msg.cmd = 6;printf("輸入您的用戶名:\n");scanf("%s",msg.msg);write(socketfd, &msg,sizeof(struct Msg)); }else{return ;}}//顯示在線好友列表; void display(int socketfd) {struct Msg msg;printf("我想知道在線的好友列表\n");msg.cmd = 5;write(socketfd, &msg, sizeof(struct Msg)); } //登錄函數; void enter(int socketfd) {struct Msg msg;msg.cmd = 4;printf("請輸入用戶名 :\n");scanf("%s",&(msg.msg));printf("請輸入用戶密碼:\n");scanf("%d",&(msg.password));write (socketfd, &msg, sizeof(msg)); //消息寫過去,等待回復,例如什么用戶不存在,密碼錯誤;if(msg.cmd == 5){}read(socketfd ,&msg ,sizeof(msg)); //讀取來自服務器的返回的消息,進行客戶端屏幕打印;//printf("%d,%d\n",msg.cmd,sizeof(msg));if(msg.cmd == 1002){printf("恭喜你登錄成功\n");//登錄完成之后開始讀寫分離;sleep(1);pthread_t id;pthread_create(&id, NULL, readMsg, (void *)socketfd);pthread_detach(id); // 線程分離 int a;while (1){interface2();printf("\n");printf("\n");sleep(1);printf("\t\t*_*輸入功能:\n");scanf("%d",&a);printf("\n");while(getchar()!= '\n');switch(a){case 1: //發(fā)送文件send_file(socketfd);break;case 2: // 群聊天chat(socketfd);break;case 3: // 私聊chat2(socketfd);break;case 4 : //注銷用戶;logout(socketfd);return;case 5: //顯示在線好友列表;display(socketfd);sleep(1);break;case 6: //查看本地聊天記錄;look_msg(socketfd);sleep(1);break;}system("clear");}}else if(msg.cmd == -1){printf("密碼不正確\n");usleep(5*100000);}else if(msg.cmd == -2){printf("該用戶不存在\n");sleep(0.5);}}//聊天記錄存到本地; int insert_msg(struct Msg* msg) { sqlite3 *database;int ret = sqlite3_open( "msg.db", &database );if(ret != SQLITE_OK){perror("sqlite3_open");return -1;}printf("數據庫打開成功\n"); //下邊一大段是創(chuàng)建一個表char *errmsg = NULL;char *sql = "create table if not exists msg (fromname TEXT, information TEXT,toname TEXT)"; //sql語句 ret = sqlite3_exec(database ,sql, NULL ,NULL ,&errmsg);//執(zhí)行sql語句的函數;if(ret != SQLITE_OK){printf("數據庫創(chuàng)建操作失敗 %s\n",errmsg);return -1;}//往表插入數據;//insert into student values(1, 'Zhang', 'M', 18);char buf[100];printf("%s\n",msg->fromname);sprintf(buf," insert into msg values('%s','%s' ,'%s')",msg->fromname ,msg->information ,msg->toname );//設置主鍵之后,如果插入的id已經存在那么就會返回錯誤,一班來說返回的錯誤都是插入重復這里有點取巧;ret = sqlite3_exec(database ,buf, NULL ,NULL ,&errmsg);if (ret != SQLITE_OK){printf ("數據庫插入操作失敗:%s\n", errmsg);return -1;}printf("聊天記錄成功保存到本地數據庫*_*\n");sqlite3_close(database);return 1; }//查看本地聊天記錄; int look_msg(int socketfd) {//本地創(chuàng)建一張數據庫表,存放本地的消息;//查看不就簡單了,直接打開本地的數據庫就好了;sqlite3 *database;int ret = sqlite3_open( "msg.db", &database );if(ret != SQLITE_OK){perror("sqlite3_open");return -1;}printf("數據庫打開成功\n"); char ** resultp;char *errmsg = NULL;int nrow;int ncolumn;//進行什么操作;char *sql = "select * from msg";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg );if(ret != SQLITE_OK){printf("數據庫操作失敗 %s\n",errmsg);return -1;}int i;printf("nrow = %d,ncolumn = %d",nrow, ncolumn);for(i = 0; i < (nrow +1)* ncolumn;i++){if(i % ncolumn == 0){printf("\n");}printf("%-18s" ,resultp[i]);}printf("\n");sqlite3_free_table(resultp); //之前的char**resultp (數組)等于malloc了一個空間來儲存數據庫的數據;所以需要釋放;sqlite3_close(database); }//傳送文件; send_file(int socketfd) {}// 客戶端向服務器發(fā)送數據處理函數; void ask_server(int socketfd) {int a ;while (1){//char ch[2];int a;while (1){printf("\n");interface();printf("\n");printf("\n");sleep(1);printf("\t\t*_*輸入功能:\n");scanf("%d",&a);printf("\n");while(getchar()!= '\n');switch(a){case 1: //注冊;reg(socketfd);printf("注冊注冊注冊\n");break;case 2: //登錄;enter(socketfd);break;}system("clear");}} }int main() { // 創(chuàng)建與服務器通信的套接字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("127.0.0.1",&(addr.sin_addr));// 連接服務器,如果成功,返回0,如果失敗,返回-1// 成功的情況下,可以通過socketfd與服務器進行通信int ret = connect(socketfd, (struct sockaddr *)&addr, sizeof(addr));if (ret == -1){perror ("connect");return -1;}printf ("成功連上服務器\n");//開始進行操作;ask_server(socketfd);// 關閉套接字close(socketfd);return 0; }總結
- 上一篇: 拿到6个重磅offer的大神,超详细面试
- 下一篇: 迅雷软件一直出现崩溃问题的常见解决方法