日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

即时通讯系统————基于TCP协议的C/S架构(Client)

發布時間:2023/12/20 windows 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 即时通讯系统————基于TCP协议的C/S架构(Client) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

客戶端頭文件

#ifndef CLIENT_H #define CLIENT_H#include <string.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <time.h> #include <unistd.h>#define FAILURE 10000 #define SUCCESS 10001 #define FALSE 10002 #define TRUE 10003#define PORT 8888 struct sockaddr_in server_addr;enum Enum {REG,LOGIN,PRIVATE,GROUP, };typedef enum Enum ENUM; struct user {char petname[32];char age[32] ;char sex[32] ;char key[32];int cmd;int member;char buf[32]; }; typedef struct user User;struct judge {int cmd;char buf[32];char petname[32];char t2[128]; }; typedef struct judge Judge;struct info {int ToFd;char petname[32];char ptr[64]; }; typedef struct info InFo;void menu(); void menu2(); void Register(int sockfd); //實現用戶注冊 int Login(int sockfd); //登錄 void showfriend(int sockfd, char ptr[32]); //顯示在線好友 int exitlogin(int sockfd, char ptr[32]); //退出登錄 int chatprivate(int sockfd, char ptr[32]); //私聊 void deposit(int sockfd, char ptr[32]); //充值會員 void checkrecord(int sockfd, char ptr[32]); //查看與某人的私聊記錄 void key(int sockfd); //修改密碼 void groupchat(int sockfd, int L, char ptr[32]); //發起群聊 void cancel(int sockfd, char ptr[32]); //注銷賬號 void groupcheck(int sockfd); //查看群聊記錄 void praise(int sockfd); //點贊好友 int convert(int sockfd, char ptr[32]); //傳輸文件 char *MyGetch(); //實現密碼不回顯 #endif

?客戶端自定義功能函數

?

/**************************************************************> File Name: ChatClient.c> Author: yangxuan> Mail: 2503327051@qq.com > Created Time: 2018年08月23日 星期四 17時39分14秒**************************************************************/#include <stdio.h> #include "Client.h" #include <stdlib.h> #include <string.h> #include <termios.h>#define MAX_PASSWD_LEN 6//全局變量 char str[32] = {0}; char petname[32] = {0}; //記下注冊的用戶名 int ret; //用來接收多個函數執行的返回值//菜單, 顯示該通訊錄所能實現的功能 void menu() {system("clear");printf("*********************************\n");printf("********1,注冊 ******************\n");printf("********2, 登錄 ******************\n");printf("********3, 查看在線好友 ***********\n");printf("********4, 私聊 ******************\n");printf("********5, 群聊 ******************\n");printf("********6, 查看群聊信息 ***********\n");printf("********7, 查看私聊記錄 ***********\n");printf("********8, 注銷帳號****************\n");printf("********9, 充值會員****************\n");printf("********10, 點贊 ******************\n");printf("********11, 退出登錄 **************\n");printf("********12, 傳輸文件 **************\n");printf("*******13,查看接受文件 ************\n");printf("******請選擇你想要的功能 ***********\n");printf("***********************************\n"); }/*作者:楊宣函數原型:void Register(int sockfd)函數解釋:自定義函數, 函數名 :Register 帶有一個int型的參數,函數返回值為void型的函數功能:實現用戶注冊帳號功能 ,若密碼輸入不一致,提示重新輸入*/ void Register(int sockfd) {system("clear"); //執行之前先清屏User SendInfo; //先定義結構體中間變量,保存用戶的注冊信息,信息錄好后再將其拷貝到結構體中char age[32] = {0};char sex[32] = {0};char key[32] = {0};char key2[32] = {0};char buf[32] = {0};printf("請給自己取個昵稱!\n");scanf("%s", petname);printf("請輸入你的年齡!\n");scanf("%s", age);printf("請輸入您的性別!\n");scanf("%s", sex);printf("請輸入六位密碼!\n");getchar(); //一定要加這句,清空緩沖區的回車鍵,下面輸密碼也要加strcpy(key, MyGetch());printf("請再次輸入密碼!\n");strcpy(key2, MyGetch());while(strcmp(key, key2) != 0){memset(key, 0, sizeof(key));memset(key2, 0, sizeof(key2));printf("您兩次密碼輸入不一致, 請重新輸入密碼!\n");printf("請輸入六位密碼!\n");strcpy(key, MyGetch());printf("請再次輸入密碼!\n");strcpy(key2, MyGetch());}strcpy(SendInfo.petname, petname);strcpy(SendInfo.age, age);strcpy(SendInfo.sex, sex);strcpy(SendInfo.key, key);SendInfo.cmd = 1;ret = send(sockfd, &SendInfo, sizeof(SendInfo), 0);if(ret == -1){perror("send3");} }/*作者:楊宣函數原型:void key(int sockfd)函數解釋:自定義函數, 函數名 :key 函數帶有一個int型的參數, 函數返回值為void型的函數功能:用戶注冊好后設置密保 */ void key(int sockfd) {User SendInfo;memset(&SendInfo, 0, sizeof(SendInfo));SendInfo.cmd = 15;strcpy(SendInfo.petname, petname); //注冊好后設置密保printf("請設置密保問題,方便日后找回密碼!\n");printf("爺爺的爸爸叫什么?\n");scanf("%s", SendInfo.age);printf("爸爸的爺爺叫什么?\n");scanf("%s", SendInfo.sex);printf("爺爺的爸爸叫什么?\n");scanf("%s", SendInfo.key);ret = send(sockfd, &SendInfo, sizeof(SendInfo), 0);if(ret == -1){perror("send3");} }/*作者:楊宣函數原型:int Login(int sockfd)函數解釋:自定義函數, 函數名 :Login 函數帶有一個int型的參數, 函數返回值為void型的函數功能:用戶登錄 */ int Login(int sockfd) {system("clear"); //每次調用的時候都清屏,提升界面視覺化體驗感int ret;char buf[32] = {0};User U;char petname[32] = {0};char key[32] = {0};printf("請輸入昵稱!\n");scanf("%s", petname);printf("請輸入密碼!\n");getchar();strcpy(key, MyGetch());strcpy(U.petname, petname);strcpy(U.key, key);U.cmd = 2;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send2");}return FAILURE; }/*作者:楊宣函數原型:void showfriend(int sockfd, char ptr[32])函數說明:自定義函數, 函數名 :showfriend 函數帶有一個int型的參數, 函數返回值為void型的函數功能:查詢在線好友*/ void showfriend(int sockfd, char ptr[32]) {system("clear");User U;U.cmd = 3;int ret;char buf[32] = {0};strcpy(U.petname, ptr);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("sendf");} }/*作者:楊宣函數原型:int exitlogin(int sockfd, char ptr[32])函數說明:自定義函數, 函數名 :exitlogin 函數帶有一個int型的參數, 函數返回值為void型的函數功能:發送用戶想要退出登錄信息給服務端 */ int exitlogin(int sockfd, char ptr[32]) {system("clear");char buf[32] = {0};printf("確認退出登錄嗎?, y or n\n"); //再次確認是否要退出scanf("%s", buf);User U;U.cmd = 11;if(strcmp(buf, "y") == 0){strcpy(U.petname, ptr);printf("ptr%s\n", U.petname);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("sendlogin");}}else{printf("謝謝你留下來, 快找好友嘮嗑吧!\n");sleep(2);return SUCCESS;}return FAILURE; }/*作者:楊宣函數原型:int chatprivate(int sockfd, char ptr[32])函數說明:自定義函數, 函數名 :chatprivate 函數帶有一個int型的參數, 一個char型的數組, 函數返回值為void型的參1:發送線程的文件描述符 參2:私聊發起人的昵稱函數功能:向服務器發送私聊申請 */ int chatprivate(int sockfd, char ptr[32]) {system("clear"); User U;char buf[32] = {0};printf("請選擇私聊對象!\n");scanf("%s", U.petname);printf("輸入發送的話\n");scanf("%s", U.age);//strcpy(U.petname, buf);strcpy(U.buf, ptr);U.cmd = 4;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("sendpri");}return 0; }/*作者:楊宣函數原型:void deposit(int sockfd, char ptr[32])函數說明:自定義函數, 函數名 :deposit 函數帶有一個int型的參數, 一個char型的數組, 函數返回值為void型的參1:發送線程的文件描述符 參2:私聊發起人的昵稱函數功能:向服務器發起 充值會員信息*/ void deposit(int sockfd, char ptr[32]) {system("clear");User U;printf("每月付費8元,可享受綠鉆會員特權!\n");printf("每月付費15元,可享受皇冠會員特權!\n");printf("每月付費20元,可享受王者特權!\n");printf("***請選擇你想要享受哪種特權****\n");printf("1, 綠鉆, 2,皇冠 3,王者 \n");scanf("%d", &U.member);U.cmd = 9;strcpy(U.petname, ptr);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("sendmem");} }/*作者:楊宣函數原型:void praise(int sockfd)函數說明:自定義函數, 函數名 :praise 函數帶有一個int型的參數, 函數返回值為void型的函數功能:發送用戶想要點贊好友的信息給客戶端 */ void praise(int sockfd) {system("clear");User U;printf("請選擇你想點贊的好友名\n");scanf("%s", U.petname);U.cmd = 10;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("sendprise");} }/*作者:楊宣函數原型:void checkrecord(int sockfd, char ptr[32])函數說明:自定義函數, 函數名 :checkrecord 函數帶有一個int型的參數, 一個char型的數組, 函數返回值為void型的參1:發送線程的文件描述符 參2:私聊發起人的昵稱函數功能:向服務器發起 查詢與某人私聊記錄 請求*/ void checkrecord(int sockfd, char ptr[32]) {system("clear");User U;printf("你想查看與哪個好友的聊天記錄\n");scanf("%s", U.petname);U.cmd = 7;strcpy(U.buf, ptr);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("sendcheck");} }/*作者:楊宣函數原型:void groupchat(int sockfd, int L, char ptr[32])函數說明:函數 帶有兩個int 型參數,一個char 型數組 返回值:void 型函數功能:發送群聊邀請給服務器*/ void groupchat(int sockfd, int L, char ptr[32]) {system("clear");User U;//L = 0;printf("請給群聊起個名字\n");scanf("%s", U.sex);while(1){printf("請輸入你想邀請進行群聊的好友名, 輸入ok 確認邀請完畢\n");scanf("%s", U.petname);if(strcmp(U.petname, "ok") == 0){printf("群聊邀請已發送!\n");break;}U.cmd = 5;strcpy(U.age, ptr);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("sendgroup");}} }/*作者:楊宣函數原型:void cancel(int sockfd, char ptr[32])函數說明:形參為套接字,該客戶端登錄賬號昵稱,返回值void函數功能:注銷賬號 */ void cancel(int sockfd, char ptr[32]) {User U;strcpy(U.petname, ptr);U.cmd = 8;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");} }/*作者:楊宣函數原型:void groupcheck(int sockfd)函數說明:形參為int 型的套接字函數功能:向服務器發送查詢群聊聊天記錄請求 */ void groupcheck(int sockfd) {User U;printf("請輸入你想查詢記錄的群名:\n");scanf("%s", U.petname);U.cmd = 6;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}}/*作者:楊宣函數原型:int convert(int sockfd, char ptr[32])函數說明:形參為套接字,該客戶端登錄賬號昵稱,返回值int函數功能:發送用戶想要傳輸文件信息給服務端 */ int convert(int sockfd, char ptr[32]) {User U;FILE *fp;Judge J;int i = 0;printf("請選擇傳輸文件的對象\n");scanf("%s", U.petname);printf("清輸入傳輸的文件名\n");scanf("%s", U.buf);fp = fopen(U.buf, "r");if(fp == NULL){printf("文件解析失敗\n");return FAILURE;}else{strcpy(U.age, ptr);U.cmd = 23;ret = send(sockfd, &U, sizeof(U), 0); //先將文件名和發送者發給客戶端if(ret == -1){perror("send");}while(1){memset(U.buf, 0, sizeof(U.buf)); //每次使用之前都要清空ret = fread(U.buf, 1,sizeof(U.buf) - 1, fp); //不斷的從文件中獲取一個buf大小, ret為讀到的字節數 if(ret == -1){perror("fread");break;}if(ret == 0) //如果ret為0,說明讀到結尾了,發送bye給服務器,說明文件傳輸完畢{strcpy(U.age, "bye");ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}break;}else {U.cmd = ret;strcpy(U.age, ptr);ret = send(sockfd, &U, sizeof(U), 0); //每次都將讀到的發送給服務器if(ret == -1){perror("send");}}}fclose(fp); //文件描述符打開后,使用完一定得關上} return SUCCESS; }/*作者:楊宣函數原型:void checkfile(int sockfd)函數說明:形參為int型的套接字函數功能:查看已接收到的文件 */ void checkfile(int sockfd) {User U;U.cmd = 24;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");} }char passwd[MAX_PASSWD_LEN];/*作者:楊宣函數原型:char *MyGetch()函數說明:自定義函數返回值char *型,不帶參數函數功能:實現密碼的不回顯 */ char *MyGetch() {int len = 0;char ch;struct termios oldt, newt;while(1){if(len < MAX_PASSWD_LEN){tcgetattr(STDIN_FILENO, &oldt);newt = oldt;newt.c_lflag &= ~(ECHO | ICANON);tcsetattr(STDIN_FILENO, TCSANOW, &newt);ch = getchar();printf("*");tcsetattr(STDIN_FILENO, TCSANOW, &oldt);}else{printf("\n");break;}passwd[len] = ch;len = len + 1;}return passwd; }

?客戶端main函數

/**************************************************************> File Name: Client.c> Author: yangxuan> Mail: 2503327051@qq.com > Created Time: 2018年08月23日 星期四 17時38分22秒**************************************************************/#include <stdio.h> #include "Client.h" #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #include <pthread.h>//全局變量 int sockfd, ret; User RecvInfo; //定義一個用戶信息結構體變量,每一次讀線程都將讀到的信息存放到此結構體中 pthread_t tid_send; //發送線程號,設成全局變量以備線程等待時使用 pthread_t tid_recv; //接收線程號 pthread_mutex_t mutex; //定義一把鎖, 線程間操作共享內存時需要用到鎖 pthread_cond_t con; //當鎖住的共享變量發生改變時,需要用pthread_cont_t這種條件變量來精準的通知某個或幾個線程,讓他們執行相應的操作 char ptr[32] = {0}; //記下客戶端登陸賬戶昵稱,以備發起私聊,群聊, 找回密碼傳參用 int amd = 0; //amd 用在控制重復登錄操作(已有帳號在線置為1),一個客戶端只能登一個帳號并且只有登錄后才能進行相關操作 int emd = 0; //emd 用來判斷是否在找回密碼(找回密碼只為1,滿足條件將發送線程掛起) int dmd = 0; //用在注冊時讓發送線程等待,因為還要判斷用戶想不想設置密保 int bmd = 1; //bmd 用來判斷是否發起私聊(bmd = 0未發起私聊, 發起私聊將bmd 置為1) int lmd = 0; //用來判斷是否收到私聊請求(收到為1) int j = 0; //計數用戶累計獲得點贊數 int L = 1; //用來計數群聊人數 int umd = 0; //判斷是否被群主設置為管理員(umd = 1為管理員) char gg[32] = {0}; //記下邀請群聊用戶名 char s[5] = {0}; int cmd; //判斷是否收到群聊邀請(cmd = 10即為收到邀請信息,若不同意則喚醒發送線程,若同意等通信完再喚醒) pthread_t tid1, tid2; //群聊時創建兩個線程專門用來發送接收 pthread_t tid3, tid4; int fmd = 0; //用來判斷是否被禁言(禁言為1 , 解禁為0) int gmd = 1; //用來判斷是否主動發起群聊(發起為1, 結束為 0) Judge G; //定義用于判斷的結構體變量 int rmd = 0; FILE *fp; int F;//sleep函數 寫在while(1)循環里, 主動告訴操作系統,這個線程暫時處理完畢(在sleep這暫停,并不是這個代碼全走完了)將線程轉入阻塞狀態,直到經過阻塞時間才會轉入就緒狀態/*作者:楊宣函數原型:void delay()函數功能:自定義一個延遲函數,用于延長結果顯示時間 */ void delay() {int x = 30000, y;while(x > 0){y = 10000;while(y > 0){y--;}x--;} }/*作者:楊宣函數原型:void *pthread(void *arg)函數說明:線程函數,形參為void *,返回值也為void *函數功能:完成群主的信息發送,是在主發送線程的case 5群聊中起的線程*/ void *groupsend(void *arg) {int old; //設置線程取消特性,若邀請的好友全部退出,則群聊自動解散,此線程也應被取消pthread_setcanceltype(0, &old);int mm, m;User U;printf("1,發送小表情 2,自定義發送 3, 群主特權\n"); while(1){scanf("%d", &mm); if(mm ==3) //行使群主權力{printf("1, 設置管理員 2, 踢人 3, 禁言, 4,解禁\n");scanf("%d", &m);if(m == 1){User U;printf("請輸入你要設置管理員的用戶\n");scanf("%s", U.petname);U.cmd = 22;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}}else if(m == 2){User U;printf("請輸入你要提出群聊的用戶!\n");scanf("%s", U.petname);U.cmd = 21;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}}else if(m == 3){User U;printf("請輸入你要禁言的用戶\n");scanf("%s", U.petname);U.cmd = 20;strcpy(U.age, "FAILURE");ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}}else{User U;printf("請輸入你要解禁的用戶\n");scanf("%s", U.petname);U.cmd = 20;strcpy(U.age, "SUCCESS");ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");} }} else if(mm == 1) //特殊符號代表小表情{printf("a: 微笑 b: 哭笑不得 c: 犯困 d: 鼓掌 e 解散群聊\n");scanf("%s", U.age);U.cmd = 19;strcpy(U.petname, ptr);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");} if(strcmp(U.age, "e") == 0){printf("你已解散群聊\n");L = 0;pthread_cond_signal(&con);pthread_exit((void *)100);}} else //用戶自定義發送,輸入bye可解散群聊{scanf("%s", U.age);U.cmd = 19;strcpy(U.petname, ptr);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");if(strcmp(U.age, "bye") == 0){printf("你已解散群聊\n");gmd = 0;L = 0;pthread_cond_signal(&con);pthread_exit((void *)100);}}}L = 1; // 群聊解散后需重新將人數為1return NULL; }/*作者:楊宣函數原型:void *pthread(void *arg)函數說明:線程函數,void *形參,返回值:void *的指針函數功能:完成進入群聊用戶的信息發送,是在接收線程的case 5群聊中起的線程*/ void *receivegroup(void *arg) {int old;pthread_setcanceltype(0, &old); //退出群聊或群主解散群聊后,都要取消該線程int m, mm;User U;printf("1,發送小表情 2,自定義發送 3, 管理員特權\n");while(1){if(fmd == 1) //禁言后將fmd為1,若不清空在線程等待之前會多發送一次{scanf("%d", &m);printf("你已被禁言,無法發送消息!\n");memset(&m, 0, sizeof(m));//break;}if(fmd != 1) {scanf("%d", &m);if(m == 3 && umd == 1) //umd = 1說明被群主設置為管理員 {printf("2, 踢人 3, 禁言, 4,解禁\n");scanf("%d", &mm);if(mm == 2){User U;printf("請輸入你要踢出群聊的用戶!\n");scanf("%s", U.petname);U.cmd = 21;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}}else if(mm == 3){User U;printf("請輸入你要禁言的用戶\n");scanf("%s", U.petname);U.cmd = 20;strcpy(U.age, "FAILURE");ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}}else{User U;printf("請輸入你要解禁的用戶\n");scanf("%s", U.petname);U.cmd = 20;strcpy(U.age, "SUCCESS");ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}}}else if(m == 3 && umd != 1){printf("你當前還不是管理員\n");}else if(m == 1){printf("a: 微笑 b: 哭笑不得 c: 犯困 d: 鼓掌 e: 退出群聊\n");scanf("%s", U.age);U.cmd = 18;strcpy(U.petname, ptr);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}if(strcmp(U.age, "e") == 0){//fmd = 1printf("你已退出群聊!\n");delay();// umd = 0;cmd = 0;pthread_cond_signal(&con);pthread_exit((void *)100);return NULL;}}else if(m == 2){User U; memset(&U, 0, sizeof(U));scanf("%s", U.age);U.cmd = 18;strcpy(U.petname, ptr);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}if(strcmp(U.age, "bye") == 0){printf("你已退出群聊!\n");delay();cmd = 0;pthread_cond_signal(&con); //退出群聊后需喚醒主發送線程,退出本線程pthread_exit((void *)100);} }} }return NULL; }void *privateSend(void *arg) {int old;pthread_setcanceltype(0, &old);int a = *(int *)arg;if(a == 1){ cc: printf(" %s: %s\n", G.buf, G.petname);memset(&G, 0, sizeof(G));printf("1,回復 2,忽略\n");scanf("%d", &a);if(a == 1){printf("%s: ", ptr);}while(1){rmd = 1;if(a == 1){User U;scanf("%s", U.buf);strcpy(U.petname, ptr);U.cmd = 13;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}if(strcmp(U.buf, "bye") == 0){printf("你已關閉私聊\n");break;}}else{pthread_cond_signal(&con);pthread_exit((void *)100);break;}}cmd = 0;pthread_cond_signal(&con);pthread_exit((void *)100);}else{cmd = 0;pthread_cond_signal(&con);pthread_exit((void *)100);}return NULL; }/*作者:楊宣函數說明:客戶端發送線程, 函數原型:void *pthread(void *arg),形參:為套接字文件描述符 返回值為void型的指針函數功能:功能不斷發送想要實現的功能所需的參數 case 1: 注冊 (需等待,確認用戶是否要設置密保) case 2: 登錄 (需等待,防止用戶密碼輸錯,重設密碼)case 3: 顯示當前在線好友 case 4:私聊 case 5:群聊(需起一個線程專門用于發送群主信息) case 6: 查看私聊記錄case 7: 查看聊天記錄 case 8:查看群聊記錄case 9:充值會員 case 10:點贊好友case 11:退出登錄 */void *pthreadsend(void *arg) {int old; //設置線程取消屬性,用戶收到ctrl + c信號,需要被取消pthread_setcanceltype(0, &old);while(1){ aa: menu(); memset(&RecvInfo, 0, sizeof(RecvInfo)); //每一次都要將結構體清空再讀scanf("%d", &RecvInfo.cmd);if(cmd == 12) //用戶收到群聊邀請,需等待若拒絕或群聊結束再喚醒主發送線程{ret = pthread_create(&tid3, NULL, privateSend, &RecvInfo.cmd);if(ret == -1){perror("privateRecv");}pthread_cond_wait(&con, &mutex);goto aa;}if(cmd == 10){ret = pthread_create(&tid2, NULL, receivegroup, &RecvInfo.cmd); //同意后起個線程用于發送信息if(ret == -1){perror("recvive");}pthread_cond_wait(&con, &mutex);}switch(RecvInfo.cmd){case 1://pthread_mutex_lock(&mutex); //若添加鎖,注冊一次后就不能再次注冊Register(sockfd);if(dmd == 0){pthread_cond_wait(&con, &mutex); //線程等待,當滿足一定條件時,線程暫停}sleep(1); //告訴操作系統,暫時執行完畢,// pthread_mutex_unlock(&mutex);break;case 2://pthread_mutex_lock(&mutex);if(amd == 1){printf("你當前已有帳號在線,請退出帳號重新登錄!\n");//sleep(2);delay();}else{ret = Login(sockfd);pthread_cond_wait(&con, &mutex);}break;case 3:if(amd != 1){printf("您當前還未登錄,請登錄后再查看在線好友!\n");delay();}else{showfriend(sockfd, ptr);}sleep(1);break;case 4:if(amd != 1){printf("您當前還未登錄,請登錄后再私聊好友!\n");delay();}else{ret = chatprivate(sockfd, ptr);if(bmd == 1){pthread_cond_wait(&con, &mutex);}}sleep(1);break;case 5:if(amd != 1){printf("您當前還未登錄,請登錄后再發起群聊!\n");delay();}else{groupchat(sockfd, L, ptr);sleep(2);pthread_create(&tid1, NULL, groupsend, NULL);if(gmd == 1){pthread_cond_wait(&con, &mutex);delay();}}break;case 6:if(amd != 1){printf("您當前還未登錄,請登錄后再查看與好友聊天記錄!\n");delay();}else{groupcheck(sockfd);pthread_cond_wait(&con, &mutex);}sleep(1);break;case 7: if(amd != 1){printf("您當前還未登錄,請登錄后再查看與好友聊天記錄!\n");delay();}else{checkrecord(sockfd, ptr);pthread_cond_wait(&con, &mutex);}sleep(1);break;case 8:if(amd != 1){printf("您當前還未登錄!\n");delay();}else{cancel(sockfd, ptr);}sleep(1);break;case 9:if(amd != 1){printf("您當前還未登錄,請登錄后再給帳號進行充值!\n");delay();}else{deposit(sockfd, ptr);}sleep(1);break;case 10:if(amd != 1){printf("您當前還未登錄,請登錄后再點贊好友!\n");delay();}else{praise(sockfd);}sleep(1);break;case 11:if(amd != 1){printf("您當前還未登錄!\n");delay();}else{ret = exitlogin(sockfd, ptr);sleep(1);if(ret == SUCCESS){amd = 0; //若退出登錄則返回SUCCESS,將amd為 0,以便下個帳號登錄并跳出循環,若沒有退出成功則跳到開頭break;}else{goto aa;}}break;case 12:ret = convert(sockfd, ptr);if(ret == SUCCESS){printf("發送成功!\n");}else{printf("發送失敗!\n");}break;case 13:checkfile(sockfd);break;} if(emd == 1 | lmd == 1) //若用戶接收私聊,正在找回密碼,需讓發送線程等待{pthread_cond_wait(&con, &mutex);sleep(2);}}return NULL; }/* 作者:楊宣函數說明:客戶端接收線程, 形參:為套接字文件描述符函數功能:不斷接收想要服務端發過來的信息 case 1: 顯示注冊結果 (1,若用戶名存在,則需重新注冊 2,兩次密碼輸入確保防止用戶手癌 3, 注冊成功后填寫密保)case 2: 顯示登錄結果 (1,用戶名輸錯,提示用戶不存在 2,密碼輸錯,提示密碼錯誤并可找回密碼或者重新輸入密碼 3,用戶已在線提示 4 用戶成功登錄) case 3: 顯示當前在線好友 (顯示某某好友在線,并統計共計多少好友在線)case 4:私聊 (私聊請求發給服務器端,服務器端驗證好友是否愿意與你私聊,若同意則可繼續聊天)case 5: 群聊(用戶主動發起群聊并成為群主,1,特殊符號代表特定的表情 2,自定義任意輸入 3,群主特權) case 6: case 7: 查看聊天記錄 (按對話形式打印)case 8:注銷用戶case 9:充值會員 (享有送花,點煙火,送愛心等特權) case 10:接收用戶群聊請求(1,同意,并另起線程發送聊天信息,在case 10中不斷打印接收的群聊信息2,不同意,喚醒主發送線程)case 11:退出登錄 (并返回主菜單) case 12:接收私聊請求,(1, 拒絕聊天 2, 接受請求并聊天, 輸入 bye 可結束聊天)case 13:接收好友點贊信息 (累計點贊數)case 14; 接受密保設置結果(失敗或成功)case 15:接收密保驗證結果 (1,驗證成功,則可設置新的密碼, 2,驗證失敗需重新輸入答案再次驗證)case 16:接收密碼找回結果(失敗或成功)*/void *pthreadrecv(void *arg) {int i = 0;char buf[32] = {0};Judge J;int old; //記下線程前一狀態,影響不大pthread_setcanceltype(0, &old); //設置線程取消特性,當客戶端接收到ctrl + c 信號,需先取消該線程, 參1:隨便取一個值 參2:取地址while(1){//pthread_mutex_lock(&mutex);memset(&J, 0, sizeof(J)); //每次使用前對結構體進行清空ret = recv(sockfd, &J, sizeof(J), 0); //將客戶端接收到的信息存入結構體中strcpy(buf, J.buf);cmd = J.cmd; //主要當接收到群聊邀請時將主發送線程掛起 即當cmd = 10if(strcmp(J.buf, "BYE") == 0) //服務端ctrl + c異常退出后會發送 BYE給客戶端 ,客戶端收到后需關閉文件描述符并取消線程{close(sockfd);pthread_cancel(tid_send); //參數為要取消的線程號break;}if(ret == -1){perror("recv");}switch(J.cmd) //根據結構體中標志位判斷顯示哪個結果{case 1:pthread_mutex_lock(&mutex);if(strcmp(J.buf, "FAILURE") == 0){printf("用戶名已存在, 請重新注冊!\n");dmd = 1;pthread_mutex_unlock(&mutex);pthread_cond_signal(&con);delay();}else{int c;printf("恭喜您注冊成功,可設置密保提高帳號安全性!\n");printf("1, 繼續設置密保 2, 去登錄\n");scanf("%d", &c);if(c == 1){User SendInfo;memset(&SendInfo, 0, sizeof(SendInfo));SendInfo.cmd = 15;printf("請設置密保問題,方便日后找回密碼!\n");printf("爺爺的爸爸叫什么?\n");scanf("%s", SendInfo.age);printf("爸爸的爺爺叫什么?\n");scanf("%s", SendInfo.sex);printf("爺爺的爸爸叫什么?\n");scanf("%s", SendInfo.key);ret = send(sockfd, &SendInfo, sizeof(SendInfo), 0);if(ret == -1){perror("send3");}dmd = 1;pthread_mutex_unlock(&mutex);pthread_cond_signal(&con);}if (c == 2){dmd = 1;pthread_mutex_unlock(&mutex);pthread_cond_signal(&con);}}dmd = 0; //操作完后一定要重新將 判斷變量置為0 break;case 2://pthread_mutex_lock(&mutex);if(strcmp(J.buf, "SUCCESS") == 0){printf("登錄成功, 您已在線!\n");delay(); //延長顯示結果pthread_cond_signal(&con);amd = 1; //用來判斷是否已有賬號登錄, 若登錄賬號則將amd置為1strcpy(ptr, J.petname); //將該客戶端登錄的用戶名記下}if(strcmp(J.buf, "FAILURE") == 0){char a[32] = {0};printf("密碼不正確, 請重新登錄!\n");printf("若忘記密碼,可憑密保找回密碼!\n");printf("是否找回密碼, y or n?\n");scanf("%s", a);if(strcmp(a, "y") == 0){emd = 1;User SendInfo;memset(&SendInfo, 0, sizeof(SendInfo));SendInfo.cmd = 16;strcpy(SendInfo.petname, J.petname);printf("請回答以下問題!\n");printf("爺爺的爸爸叫什么?\n");scanf("%s", SendInfo.age);printf("爸爸的爺爺叫什么?\n");scanf("%s", SendInfo.sex);printf("爺爺的爸爸叫什么?\n");scanf("%s", SendInfo.key);ret = send(sockfd, &SendInfo, sizeof(SendInfo), 0);if(ret == -1){perror("send3");}}else{pthread_cond_signal(&con);break;}}if(strcmp(J.buf, "FALSE") == 0){printf("用戶不存在, 可嘗試退出重登!\n");delay();pthread_cond_signal(&con);}if(strcmp(J.buf, "TRUE") == 0){printf("用戶已在線!\n");delay();pthread_cond_signal(&con);}//pthread_mutex_unlock(&mutex);break;case 3:while(1) //服務器用一個循環發送,客戶端也用一個循環接受{if(strcmp(J.buf, "SUCCESS") == 0) //信息接收完畢,會接收到SUCCESS,直接跳出循環{break;}/*else if(strcmp(J.buf, "FAILURE") == 0){printf("當前無好友在線!\n");delay();break;}*/else{printf("你的好友 %s 在線上!\n", J.buf);i++;}ret = recv(sockfd, &J, sizeof(J), 0); //不斷的接收好友在線信息if(ret == -1){perror("recv");}}printf("當前在線好友數為 %d\n", i);delay();i = 0; //每次顯示完須將計數 i置為0, 不然下次再查看時會累加break;case 4:if(strcmp(J.buf, "bye") == 0) {bmd = 0;printf("好友關閉了私聊!\n");pthread_cond_signal(&con);}else{if(strcmp(J.buf, "FALSE") == 0){printf("該用戶不存在!\n");delay();bmd = 0;pthread_cond_signal(&con);//sleep(2);}else if(strcmp(J.buf, "FAILURE") == 0){printf("該好友暫時不在線!\n");delay();bmd = 0;pthread_cond_signal(&con);}else if(strcmp(J.buf, "SUCCESS") == 0){printf("發送成功!\n");delay();system("clear");}else{int a = 0;User U;//system("clear");printf("%s 回復了你 \n", J.petname);printf("1,點擊查看, 2, 忽略\n");scanf("%d", &a);if(a == 1){printf(" %s: %s\n", J.buf, J.petname);printf("1, 回復 2,忽略\n");scanf("%d", &a);while(1){if(a == 1){printf("%s: ", ptr);scanf("%s", U.buf);strcpy(U.petname, ptr);U.cmd = 12;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}if(strcmp(U.buf, "bye") == 0){printf("你已關閉私聊\n");bmd = 0;pthread_cond_signal(&con);break;}memset(&J, 0, sizeof(J));ret = recv(sockfd, &J, sizeof(J), 0);if(ret == -1){perror("recv");}printf(" %s :%s\n", J.buf, J.petname);if(strcmp(J.buf, "bye") == 0){printf("對方關閉私聊\n");bmd = 0;pthread_cond_signal(&con);break;}}else{bmd = 0;pthread_cond_signal(&con);break;}}}else{bmd = 0;pthread_cond_signal(&con);break;}}/*if(strcmp(J.buf, "對方已接受你的邀請") == 0){User U;printf("快發送消息與好友聊天吧!\n");*//*scanf("%s", U.buf);printf(" :%s\n ", ptr);U.cmd = 12;ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("chatsend");}if(strcmp(U.buf, "bye") == 0){printf("你已關閉私聊\n");umd = 0;pthread_cond_signal(&con);}*//* else if(strcmp(J.buf, "對方拒絕你的聊天邀請") == 0){bmd = 0;pthread_cond_signal(&con);}else{printf("%s :%s\n", J.petname, J.buf);User U;scanf("%s", U.buf);printf("%s :", ptr);printf("%s\n", U.buf);U.cmd = 12;strcpy(U.petname, ptr);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){ perror("chatsend");}if(strcmp(U.buf, "bye") == 0){ bmd = 0;pthread_cond_signal(&con);}}*/}bmd = 1;break;case 5:if(strcmp(J.buf, "FALSE") == 0){printf("%s 該好友暫時不在線\n", J.petname);delay();}else if(strcmp(J.buf, "FAILURE") == 0){printf("%s 拒絕了你的群聊邀請!\n", J.petname);delay();}else if(strcmp(J.buf, "SUCCESS") == 0){int mm;User U;system("clear");//pthread_create(&tid1, NULL, groupsend, NULL);printf("%s 進入群聊!\n", J.petname);L++;printf("當前群聊人數%d\n", L);/*if(L == 2){pthread_cond_signal(&con);}*/}else{if(strcmp(J.buf, "a") == 0){printf("%s 發送了一個 微笑 !\n", J.petname); }else if(strcmp(J.buf, "b") == 0){printf("%s 發送了一個 哭笑不得 !\n", J.petname);}else if(strcmp(J.buf, "c") == 0){printf("%s 發送了一個 犯困!\n", J.petname);}else if(strcmp(J.buf, "d") == 0){printf("%s 發送了一個 鼓掌 !\n", J.petname);}else if(strcmp(J.buf, "e") == 0 || strcmp(J.buf, "bye") == 0){printf("%s 退出了群聊!\n", J.petname);L--;printf("當前群聊人數%d\n", L);if(L <= 1){gmd = 0;pthread_cancel(tid1);pthread_cond_signal(&con);}}else{printf("%s : %s\n", J.petname, J.buf);}}break;case 6:while(strcmp(J.buf, "SUCCESS") != 0){printf("Jcmd%d\n", J.cmd);printf("%s : ", J.petname);printf("%s", J.buf);printf("%s\n", J.t2);memset(&J, 0, sizeof(J));ret = recv(sockfd, &J, sizeof(J), 0);if(ret == -1){perror("recv");}}delay();pthread_cond_signal(&con);break;case 7:while(strcmp(J.buf, "SUCCESS") != 0){printf("%s : ", J.petname);printf("%s ", J.buf);printf("%s\n", J.t2);memset(&J, 0, sizeof(J));ret = recv(sockfd, &J, sizeof(J), 0);if(ret == -1){perror("recv");}}delay();pthread_cond_signal(&con);break;case 8:if(strcmp(J.buf, "SUCCESS") == 0){printf("注銷成功!\n");amd = 0;}else{printf("注銷失敗\n");}break;case 9:if(strcmp(J.buf, "SUCCESS") == 0){printf("恭喜你充值成功\n");}else{printf("充值失敗\n");}break;case 10:system("clear");printf("%s 邀請你進行群聊\n", J.buf);printf("是否同意? y or n\n");scanf("%s", s);User U;strcpy(U.sex, s);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("send");}if(strcmp(s, "y") == 0){//umd = 1;User U;strcpy(gg, J.buf); //記下群聊邀請人的昵稱system("clear");printf("你已進入群聊,可以和成員進行聊天拉!\n");L++;printf("當前群聊人數 %d\n", L);}else{printf("你已拒絕群聊邀請!\n");delay();pthread_cond_signal(&con); //拒絕后喚醒主發送線程}break;case 11:if(strcmp(buf, "SUCCESS") == 0){printf("你已下線!\n");bmd--;amd = 0;//sleep(2);delay();}else{printf("下線失敗, 請稍后再試!\n");//sleep(2);delay();}break;case 12:if(rmd == 0){system("clear");printf("你收到一條新信息, 1, 點擊查看 2,忽略\n");G = J;}if(rmd == 1){if(strcmp(J.buf, "bye") == 0){pthread_cancel(tid3);cmd = 0;pthread_cond_signal(&con);sleep(2);}else{printf(" %s :%s\n", J.buf, J.petname);printf("%s: \n", ptr);}}break;case 13:printf("%s\n", J.buf);j++;printf("您的累計點贊數為 %d\n", j);break;case 14:if(strcmp(J.buf, "SUCCESS") == 0){printf("密保設置成功!\n");}else{printf("設置失敗!\n");}break;case 15:if(strcmp(J.buf, "FALSE") == 0){User U;U.cmd = 17;printf("請設置新的六位密碼!\n");//scanf("%s", U.key);getchar();strcpy(U.key, MyGetch());strcpy(U.petname, ptr);ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("sendfind");}}else{pthread_mutex_lock(&mutex);printf("問題回答有誤!請重新回答\n");User SendInfo;memset(&SendInfo, 0, sizeof(SendInfo));SendInfo.cmd = 16;/* printf("請輸入用戶名!\n");scanf("%s", SendInfo.petname);strcpy(find, SendInfo.petname);*/strcpy(SendInfo.petname, ptr);printf("請回答以下問題!\n");printf("爺爺的爸爸叫什么?\n");scanf("%s", SendInfo.age);printf("爸爸的爺爺叫什么?\n");scanf("%s", SendInfo.sex);printf("爺爺的爸爸叫什么?\n");scanf("%s", SendInfo.key);ret = send(sockfd, &SendInfo, sizeof(SendInfo), 0);if(ret == -1){perror("send3");}pthread_mutex_unlock(&mutex);}break;case 16:if(strcmp(J.buf, "SUCCESS") == 0){printf("密碼找回成功!\n");delay();emd = 0;pthread_cond_signal(&con);}else{printf("找回失敗!\n");emd = 0;pthread_cond_signal(&con);delay();}break;case 17:if(strcmp(J.buf, "a") == 0){printf("%s 發送了一個 微笑 !\n", J.petname);}else if(strcmp(J.buf, "b") == 0){printf("%s 發送了一個 哭笑不得 !\n", J.petname);}else if(strcmp(J.buf, "c") == 0){printf("%s 發送了一個 犯困!\n", J.petname);}else if(strcmp(J.buf, "d") == 0){printf("%s 發送了一個 鼓掌 !\n", J.petname);}else if((strcmp(J.buf, "e") == 0 && strcmp(J.petname, gg) == 0) || (strcmp(J.buf, "bye") == 0 && strcmp(J.petname, gg) == 0)){//fmd = 1;printf("群主解散群聊!\n");delay();//umd = 0;cmd = 0;pthread_cancel(tid2);pthread_cond_signal(&con);}else if(strcmp(J.buf, "SUCCESS") == 0){printf("%s 進入群聊\n", J.petname);L++;printf("當前群聊人數 %d\n", L);}else if((strcmp(J.buf, "e") == 0 && strcmp(J.petname, gg) != 0) || (strcmp(J.buf, "bye") == 0 && strcmp(J.petname, gg) != 0)){printf("%s 退出了群聊\n", J.petname);}else if(strcmp(J.buf, "FAILURE") == 0){printf("你已被管理員禁言\n");fmd = 1;delay();// pthread_cond_signal(&con);}else if(strcmp(J.buf, "TRUE") == 0){//cmd = 10;printf("你已被管理員解禁!\n");delay();fmd = 0;//pthread_cond_signal(&con);}else if(strcmp(J.buf, "FALSE") == 0){printf("你已被踢出群聊\n");pthread_cancel(tid2);cmd = 0;L--;pthread_cond_signal(&con);}else if(strcmp(J.buf, "TRUE") == 0){printf("你已被設置為管理員\n");umd = 1;}else{printf("%s : %s\n", J.petname, J.buf);}break;case 18:fp = fopen("file.c", "w+");if(fp == NULL){printf("文件打開失敗\n");}printf("%s 向你發送文件 %s\n", J.petname, J.buf);while(1){ret = recv(sockfd, &J, sizeof(J), 0);if(ret == -1){perror("recv");}if(strcmp(J.buf, "SUCCESS") == 0){printf("接收成功\n");break;}ret = fwrite(J.buf, 1, J.cmd, fp);if(ret == -1){perror("fwrite");}memset(J.buf, 0, sizeof(J.buf));}fclose(fp); //打開后一定要關閉break;case 19:while(1){if(strcmp(J.buf, "SUCCESS") == 0){if(F == 0){printf("暫無已接收文件\n");}break;}printf("接收來自%s 的 %s 文件\n", J.petname, J.buf);F++;ret = recv(sockfd, &J, sizeof(J), 0);if(ret == -1){perror("recv");}}break;}//pthread_mutex_unlock(&mutex);}return NULL; }/*作者:楊宣函數說明:void stopClient(int num),形參為int型,返回值為void 函數功能:關閉客戶端,當捕捉到ctrl+c信號時執行此函數,向服務端發送BYE, 告知服務端可關閉該客戶端的文件描述符并在客戶端也關閉sockfd ,并取消線程*/ void stopClient(int num) {User U;strcpy(U.petname, "BYE");if(amd == 1){U.cmd = 1;strcpy(U.buf, ptr);}ret = send(sockfd, &U, sizeof(U), 0);if(ret == -1){perror("sendstop");}close(sockfd);pthread_cancel(tid_recv);pthread_cancel(tid_send); }/*作者:楊宣函數說明:main()函數,完成sockfd 創建初始化*/ int main() {char buf[128] = {0};int length = sizeof(server_addr);pthread_mutex_init(&mutex, NULL); //初始化鎖和條件變量pthread_cond_init(&con, NULL);signal(SIGINT, stopClient); //捕捉信號ctrl+c,執行stopClient函數sockfd = socket(PF_INET, SOCK_STREAM, 0); //創建一個sockfd,采用ipv4 協議,基于流的發送機制if(sockfd == -1){perror("sockfd");exit(1);}//初始化服務端結構體變量memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = PF_INET;server_addr.sin_port = htons(PORT); //要想雙方通信,需用htons(相同端口號)server_addr.sin_addr.s_addr = inet_addr("192.168.1.113"); //參數為服務器的虛擬機IP地址//向服務端發起連接ret = connect(sockfd, (struct sockaddr *)&server_addr, (socklen_t)length);if(ret == -1){perror("connect");}//創建兩個線程,一個用來發送,一個接收ret = pthread_create(&tid_send, NULL, pthreadsend, &sockfd); if (ret != 0){perror("pthread_createsend");exit(1);}ret = pthread_create(&tid_recv, NULL, pthreadrecv, &sockfd);if (ret != 0){perror("pthread_createrecv");exit(1);}//線程等待,若不加來不及等main()函數分配到的運行時間使用完,線程就會立即死掉,不會出任何結果void *status;pthread_join(tid_send, &status);pthread_join(tid_recv, &status);return 0; }

?

?

?

?

?

總結

以上是生活随笔為你收集整理的即时通讯系统————基于TCP协议的C/S架构(Client)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。