基於Linux c 用socket和執行緒 實現的簡易聊天室之伺服器
阿新 • • 發佈:2019-02-17
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sqlite3.h>
#define PORTNUMBER 9994
#define MAXNUM 10
#define OK 1
#define ERROR 0
typedef int Elementtype;
typedef int Status;
//與客戶端一致的結構體
typedef struct client
{
Elementtype id;
Elementtype flag;
Elementtype case_num;//伺服器進行功能選擇
Elementtype case_numnext;//登入成功聊天功能選擇
char name[100];
char password[150];
//char content_c[1024];//接收客戶端傳送訊息
}Client_message;
//定義一個伺服器的結構體
typedef struct server
{
Elementtype i_s;
Elementtype num_s[10];
Elementtype case_snum;//伺服器傳送進行的功能 0註冊成功,1登入失敗,2普通使用者登入,3管理員登入
Elementtype id__s; //4私聊時查詢ID有人,5私聊查詢ID沒人,6查詢線上人數
char name_s[100];
char password_s[150];
//char content_s[1024];//伺服器傳送的訊息快取區
}Server_message;
//連結串列結構體
typedef struct node
{
int id_l;
int fd_l;
struct node *next;
}linkedlist;
Client_message msg_accept;//定義一個全域性的結構體名字,接收客戶端的結構體
Server_message msg_send;//定義一個全域性的結構體名字,傳送伺服器的結構體
linkedlist *list;
//連結串列函式
linkedlist *createlinkedlist();
int getcount(linkedlist *list);
//void insert1(linkedlist *list, int id, int fd);
linkedlist *insert2(linkedlist *list, int id, int fd);
int queryfd(linkedlist *list, int id);
int queryid(linkedlist *list, int fd);
void printf_list(linkedlist *list);
linkedlist *dellinkedlist(linkedlist *list, int fd);
void *func(void * arg);
int newfd;//定義一個全域性整形的套接字
int main(int argc, char *argv[])
{
system("clear");
//message msg_accept;
int ret;
printf("伺服器正在初始化......\n");
sleep(2);
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == socket_fd)
{
perror("建立通訊失敗");
exit(1);
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORTNUMBER);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("初始化伺服器成功......\n");
printf("正在啟動伺服器......\n");
sleep(2);
if (-1 == bind(socket_fd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)))
{
perror("繫結地址失敗");
exit(2);
}
if(-1 == listen(socket_fd, MAXNUM))//最大監聽使用者人數為10
{
perror("監聽失敗");
exit(3);
}
printf("伺服器啟動成功......\n");
sqlite3 *db;
ret = sqlite3_open("./server.db", &db);//開啟資料庫
if(ret != SQLITE_OK)
{
printf("開啟資料庫失敗\n");
}
printf("開啟資料庫成功......\n");
printf("正在等待客戶端的連線......\n");
ret = sqlite3_close(db);
if(ret != SQLITE_OK)
{
printf("關閉資料庫失敗\n");
}
//建立一個單鏈表
list = createlinkedlist();
pthread_t pid;
while(1)
{
struct sockaddr_in client_addr;
int length = sizeof(struct sockaddr);
newfd = accept(socket_fd, (struct sockaddr *)(&client_addr), &length);
if (-1 == newfd)
{
perror("接收失敗");
exit(1);
}
printf("客服端%d連上了伺服器......\n",newfd);
pthread_create(&pid,NULL,(void*)func,(void*)newfd);
}
//close(newfd);
return 0;
}
void *func(void * arg)
{
int newfd = (int)arg;//強轉為套接字型別
char sendbuff[1024] = {0};//伺服器傳送資訊
char buff[1024] = {0};//把套接字先快取到的區域
int ret;
static int num = 1000;//用作ID
// message *msg_accept = (message *)arg ;//把arg強轉為結構體
while(1)
{
ret = read(newfd, buff,1024);
if(-1 == ret)
{
perror("讀取錯誤");
exit(1);
}
memset(&msg_accept,0,sizeof(msg_accept));//清空結構體
memcpy(&msg_accept,buff,sizeof(msg_accept));//把收到的資訊轉換為結構體
//printf("msg_accept.name = %s\t,msg_accept.password = %s\n",msg_accept.name,msg_accept.password);
//printf("msg_accept.case_num = %d\n",msg_accept.case_num);
switch(msg_accept.case_num)
{
case 1 : //客戶請求註冊
{
printf("---------------------------------------------\n");
printf("客戶端需要註冊的名字為: %s 密碼 :%s\n",msg_accept.name,msg_accept.password);
printf("---------------------------------------------\n");
sqlite3 *db;
char *errmsg;
ret = sqlite3_open("server.db",&db);
if(ret != SQLITE_OK)
{
perror("開啟資料庫失敗");
exit(2);
}
char sql_insert[1024] = {0};
sprintf(sql_insert,"insert into server(id ,name,password) values(%d,'%s','%s');",num,msg_accept.name,msg_accept.password);
printf("----------------------以下資訊已進入資料庫-----------------------\n");
printf("%s\n",sql_insert);
printf("-----------------------------------------------------------------\n");
ret = sqlite3_exec(db,sql_insert,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
perror("插入資料庫失敗");
exit(3);
}
ret = sqlite3_close(db);
if(ret != SQLITE_OK)
{
perror("關閉資料庫失敗");
exit(4);
}
msg_send.case_snum = 0;
msg_send.id__s = num;
num++;
memset(sendbuff,0,1024);
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
case 2: //客戶請求登入
{
printf("---------------------------------------------\n");
printf("有客戶需要登入, 登入ID:%d 密碼:%s \n",msg_accept.id,msg_accept.password);
printf("---------------------------------------------\n");
sqlite3 *db;
char *errmsg;
int row;
int column;
char**result;
ret = sqlite3_open("server.db",&db);
if(ret != SQLITE_OK)
{
perror("開啟資料庫失敗");
exit(2);
}
char sql_client[1024] = {0};
sprintf(sql_client,"select id,password from server where id = %d and password = '%s';",msg_accept.id,msg_accept.password);
ret = sqlite3_get_table(db, sql_client, &result, &row, &column, &errmsg);
if(ret != SQLITE_OK)
{
perror("查詢資料庫失敗");
exit(3);
}
int i;
int j;
printf("-------查詢結果如下--------\n");
for(i = 1;i <= row;i++)
{
for(j = 0;j < column;j++)
{
printf("%s|",result[i * column + j]);
}
printf("\n");
}
printf("---------------------------\n");
ret = sqlite3_close(db);
if(ret != SQLITE_OK)
{
perror("關閉資料庫失敗");
exit(4);
}
if(column == 0)
{
printf("你登入的資訊有誤,請重新登入.\n");
msg_send.case_snum = 1;
memset(sendbuff,0,1024);
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
else//登入成功
{
printf("恭喜你登入成功.\n");
if(msg_accept.id == 1000)//管理員登入
{
memset(sendbuff,0,1024);
printf("管理員上線.\n");
msg_send.case_snum = 3;//管理登入成功後傳送到客戶端的指令
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
}
else //普通使用者登入成功
{
memset(sendbuff,0,1024);
printf("普通使用者上線.\n");
msg_send.case_snum = 2;//普通使用者登入成功後傳送到客戶端的指令
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
}
//插入資訊到連結串列
list = insert2(list, msg_accept.id, newfd);
printf("現在線上人物資訊 :\n");
printf_list(list);
printf("線上人數為:%d\n", getcount(list));
while(1)
{
memset(buff,0,1024);
ret = read(newfd,buff,1024);
if(-1 == ret)
{
perror("讀取失敗");
exit(1);
}
memcpy(&msg_accept,buff,sizeof(msg_accept));
switch(msg_accept.case_numnext)
{
case 1://檢視當前人數
{
/*
char str[1024] = {0};
sprintf(str,"當前線上人數為: %d\n",count);
ret = write(newfd,str,1024);
if(-1 == ret)
{
perror("寫入人數失敗");
exit(2);
}
*/
int count = getcount(list);//用連結串列檢視當前的人數
memset(sendbuff ,0 ,1024);
msg_send.id__s = count;//用作id_s臨時記錄下線上的人數
printf("count = %d\n",msg_send.id__s);
msg_send.case_snum = 6;//查詢線上人數
//memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
sleep(1);
linkedlist *h = list;
int temp = 0;
while(h != NULL)
{
msg_send.num_s[temp] = h -> id_l;
temp++;
h = h -> next;
}
msg_send.i_s = temp;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
case 2: //傳送私聊
{
int send_newfd = queryfd(list, msg_accept.id);//查詢私聊人物的FLAG
//是否有此人
// printf("查到的客戶端是: %d\n", send_newfd);
int id_client = queryid(list,newfd);//查詢傳送訊息人物的ID
//printf("id_client = %d\n",id_client);//列印他的ID
if(send_newfd != 0)//有此人
{
printf("客戶端%d 私聊客戶端%d 訊息為 : %s\n",newfd,send_newfd,msg_accept.name);
memset(sendbuff ,0 ,1024);
msg_send.id__s = send_newfd;//用作id_s臨時記錄下客戶端的FLAG
msg_send.case_snum = 4;//查詢有這個ID
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
memset(sendbuff,0,1024);
strcpy(msg_send.name_s,msg_accept.name);
msg_send.case_snum = 7;//用於傳送私聊訊息的指令
msg_send.id__s = id_client;//用於記錄傳送人的ID
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(send_newfd,sendbuff,1024);//傳送給要私聊的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
memset(sendbuff,0,1024);
msg_send.case_snum = 8;//用於發聵訊息傳送成功了指令
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給發起私聊的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
}
else
{
printf("沒有這個ID\n");
memset(sendbuff ,0 ,1024);
msg_send.case_snum = 5;//沒有這個ID
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
}
break;
}
case 3: //傳送群聊
{
int id_client = queryid(list,newfd);//查詢傳送群聊訊息人物的ID
printf("客戶端%d發起了群聊,內容是:%s\n",newfd,msg_accept.name);
int i;
linkedlist *h = list;
//把線上人數都遍歷出來
for(i = 0; i < getcount(list); i++)
{
if(h -> fd_l != newfd)
{
memset(sendbuff, 0, 1024);
strcpy(msg_send.name_s,msg_accept.name);//複製群聊的訊息到伺服器的結構體裡面
msg_send.case_snum = 9;//用於傳送群聊訊息的指令
msg_send.id__s = id_client;//用於記錄傳送人的ID
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(h -> fd_l, sendbuff, 1024);
if(-1 == ret)
{
perror("write");
exit(EXIT_FAILURE);
}
}
h = h -> next;
}
memset(sendbuff,0,1024);
msg_send.case_snum = 10;//用於發聵訊息傳送成功了指令
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給發起群聊的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
case 4: //客戶請求傳送檔案
{
int ret;
int accept_newfd = queryfd(list, msg_accept.id);//查詢檔案要傳送到人物的FLAG
int id_send = queryid(list,newfd);//查詢傳送檔案的ID
printf("客戶端%d請求傳送檔案給客戶端%d,檔名是: %s\n",newfd,accept_newfd,msg_accept.name);
memset(sendbuff,0,1024);
//先把名字發給要接受檔案的人
msg_send.case_snum = 18;
msg_send.id__s = id_send;
strcpy(msg_send.name_s,msg_accept.name);
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(accept_newfd,sendbuff,1024);
if(-1 == ret)
{
perror("寫入失敗\n");
exit(1);
}
//把內容發給要接受檔案的人
while(1)
{
char buffer_file[1024];
memset(buffer_file, 0, 1024);//清空快取
if(recv(newfd, buffer_file, 1024, 0) < 0)
{
perror("接收失敗");
exit(1);
}
printf("內容是 :\n");
printf("%s\n",buffer_file);
if(send(accept_newfd, buffer_file, 1024, 0) < 0)
{
perror("傳送失敗");
exit(1);
}
if(0 == strncmp(buffer_file, "END", 3))
{
break;
}
}
//把傳送成功的訊息發聵給傳送者
memset(sendbuff,1024,0);
msg_send.case_snum = 19;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);
if(-1 == ret)
{
perror("寫入失敗\n");
exit(1);
}
break;
}
case 5: //客戶請求下線
{
printf("客戶端%d請求下線\n",newfd);
list = dellinkedlist(list, newfd);
printf_list(list);
memset(sendbuff,0,1024);
msg_send.case_snum = 11;//用於發聵訊息傳送成功了指令
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給發起請求下線的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
//break;
goto out;
}
case 6://禁言
{
printf("管理員請求禁言,禁言的ID是%d\n",msg_accept.id);
memset(sendbuff, 0, 1024);
int jinyan_newfd = queryfd(list,msg_accept.id);//查詢被禁言人的客戶端
msg_send.case_snum = 12;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(jinyan_newfd,sendbuff,1024);//傳送給被禁言的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
//禁言成功反饋給管理員
msg_send.case_snum = 13;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給被禁言的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
case 7://解禁
{
printf("管理員請求解禁,解禁的ID是%d\n",msg_accept.id);
memset(sendbuff, 0, 1024);
int jiejin_newfd = queryfd(list,msg_accept.id);//查詢被禁言人的客戶端
msg_send.case_snum = 14;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(jiejin_newfd,sendbuff,1024);//傳送給被禁言的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
//解禁成功反饋給管理員
msg_send.case_snum = 15;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給管理員
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
case 8://踢人下線
{
printf("管理員請求踢人,被踢人的ID是%d\n",msg_accept.id);
memset(sendbuff, 0, 1024);
int tiren_newfd = queryfd(list,msg_accept.id);//查詢被踢人的客戶端
msg_send.case_snum = 16;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(tiren_newfd,sendbuff,1024);//傳送給被踢的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
//踢人成功反饋給管理員
msg_send.case_snum = 17;
memset(sendbuff, 0, 1024);
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給管理員
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
}
}
break;
}
break;
}
case 3:
{
printf("客戶端%d請求退出\n",newfd);
goto outroom;
}
}//switch
out:
printf("-----------\n");
}//while(1)
outroom:
close(newfd);
}
linkedlist *createlinkedlist()
{
linkedlist *h;
h = NULL;
return h;
}
linkedlist *dellinkedlist(linkedlist *list, int fd)
{
linkedlist *p = list -> next;
linkedlist *h = list;
if(list -> fd_l == fd)
{
free(h);
return list -> next;
}
else
{
while(p -> fd_l != fd)
{
p = p -> next;
h = h -> next;
}
h -> next = p -> next;
free(p);
return list;
}
}
linkedlist *insert2(linkedlist *list, int id, int fd)
{
linkedlist *head, *p;
head = list;
p = (linkedlist *)malloc(sizeof(linkedlist));
if(head == NULL)
{
head = p;
p -> next = NULL;
}
else
{
p -> next = head;
head = p;
}
p -> id_l = id;
p -> fd_l = fd;
return head;
}
int getcount(linkedlist *list)
{
linkedlist *h = list;
int count = 0;
while(h != NULL)
{
count++;
h = h -> next;
}
return count;
}
int queryid(linkedlist *list, int fd)
{
linkedlist *p, *h;
h = list;
while(h != NULL)
{
if(fd == h -> fd_l)
{
return h -> id_l;
}
h = h -> next;
}
}
int queryfd(linkedlist *list, int id)
{
linkedlist *h = list;
while(h != NULL)
{
if(id == h -> id_l)
{
return h -> fd_l;
}
h = h -> next;
}
return 0;
}
void printf_list(linkedlist *list)
{
linkedlist *h = list;
while(h != NULL)
{
printf("線上人物的ID為 :%d FLAG : %d\n", h ->id_l, h -> fd_l);
h = h -> next;
}
printf("\n");
}
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sqlite3.h>
#define PORTNUMBER 9994
#define MAXNUM 10
#define OK 1
#define ERROR 0
typedef int Elementtype;
typedef int Status;
//與客戶端一致的結構體
typedef struct client
{
Elementtype id;
Elementtype flag;
Elementtype case_num;//伺服器進行功能選擇
Elementtype case_numnext;//登入成功聊天功能選擇
char name[100];
char password[150];
//char content_c[1024];//接收客戶端傳送訊息
}Client_message;
//定義一個伺服器的結構體
typedef struct server
{
Elementtype i_s;
Elementtype num_s[10];
Elementtype case_snum;//伺服器傳送進行的功能 0註冊成功,1登入失敗,2普通使用者登入,3管理員登入
Elementtype id__s; //4私聊時查詢ID有人,5私聊查詢ID沒人,6查詢線上人數
char name_s[100];
char password_s[150];
//char content_s[1024];//伺服器傳送的訊息快取區
}Server_message;
//連結串列結構體
typedef struct node
{
int id_l;
int fd_l;
struct node *next;
}linkedlist;
Client_message msg_accept;//定義一個全域性的結構體名字,接收客戶端的結構體
Server_message msg_send;//定義一個全域性的結構體名字,傳送伺服器的結構體
linkedlist *list;
//連結串列函式
linkedlist *createlinkedlist();
int getcount(linkedlist *list);
//void insert1(linkedlist *list, int id, int fd);
linkedlist *insert2(linkedlist *list, int id, int fd);
int queryfd(linkedlist *list, int id);
int queryid(linkedlist *list, int fd);
void printf_list(linkedlist *list);
linkedlist *dellinkedlist(linkedlist *list, int fd);
void *func(void * arg);
int newfd;//定義一個全域性整形的套接字
int main(int argc, char *argv[])
{
system("clear");
//message msg_accept;
int ret;
printf("伺服器正在初始化......\n");
sleep(2);
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == socket_fd)
{
perror("建立通訊失敗");
exit(1);
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORTNUMBER);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("初始化伺服器成功......\n");
printf("正在啟動伺服器......\n");
sleep(2);
if (-1 == bind(socket_fd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)))
{
perror("繫結地址失敗");
exit(2);
}
if(-1 == listen(socket_fd, MAXNUM))//最大監聽使用者人數為10
{
perror("監聽失敗");
exit(3);
}
printf("伺服器啟動成功......\n");
sqlite3 *db;
ret = sqlite3_open("./server.db", &db);//開啟資料庫
if(ret != SQLITE_OK)
{
printf("開啟資料庫失敗\n");
}
printf("開啟資料庫成功......\n");
printf("正在等待客戶端的連線......\n");
ret = sqlite3_close(db);
if(ret != SQLITE_OK)
{
printf("關閉資料庫失敗\n");
}
//建立一個單鏈表
list = createlinkedlist();
pthread_t pid;
while(1)
{
struct sockaddr_in client_addr;
int length = sizeof(struct sockaddr);
newfd = accept(socket_fd, (struct sockaddr *)(&client_addr), &length);
if (-1 == newfd)
{
perror("接收失敗");
exit(1);
}
printf("客服端%d連上了伺服器......\n",newfd);
pthread_create(&pid,NULL,(void*)func,(void*)newfd);
}
//close(newfd);
return 0;
}
void *func(void * arg)
{
int newfd = (int)arg;//強轉為套接字型別
char sendbuff[1024] = {0};//伺服器傳送資訊
char buff[1024] = {0};//把套接字先快取到的區域
int ret;
static int num = 1000;//用作ID
// message *msg_accept = (message *)arg ;//把arg強轉為結構體
while(1)
{
ret = read(newfd, buff,1024);
if(-1 == ret)
{
perror("讀取錯誤");
exit(1);
}
memset(&msg_accept,0,sizeof(msg_accept));//清空結構體
memcpy(&msg_accept,buff,sizeof(msg_accept));//把收到的資訊轉換為結構體
//printf("msg_accept.name = %s\t,msg_accept.password = %s\n",msg_accept.name,msg_accept.password);
//printf("msg_accept.case_num = %d\n",msg_accept.case_num);
switch(msg_accept.case_num)
{
case 1 : //客戶請求註冊
{
printf("---------------------------------------------\n");
printf("客戶端需要註冊的名字為: %s 密碼 :%s\n",msg_accept.name,msg_accept.password);
printf("---------------------------------------------\n");
sqlite3 *db;
char *errmsg;
ret = sqlite3_open("server.db",&db);
if(ret != SQLITE_OK)
{
perror("開啟資料庫失敗");
exit(2);
}
char sql_insert[1024] = {0};
sprintf(sql_insert,"insert into server(id ,name,password) values(%d,'%s','%s');",num,msg_accept.name,msg_accept.password);
printf("----------------------以下資訊已進入資料庫-----------------------\n");
printf("%s\n",sql_insert);
printf("-----------------------------------------------------------------\n");
ret = sqlite3_exec(db,sql_insert,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
perror("插入資料庫失敗");
exit(3);
}
ret = sqlite3_close(db);
if(ret != SQLITE_OK)
{
perror("關閉資料庫失敗");
exit(4);
}
msg_send.case_snum = 0;
msg_send.id__s = num;
num++;
memset(sendbuff,0,1024);
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
case 2: //客戶請求登入
{
printf("---------------------------------------------\n");
printf("有客戶需要登入, 登入ID:%d 密碼:%s \n",msg_accept.id,msg_accept.password);
printf("---------------------------------------------\n");
sqlite3 *db;
char *errmsg;
int row;
int column;
char**result;
ret = sqlite3_open("server.db",&db);
if(ret != SQLITE_OK)
{
perror("開啟資料庫失敗");
exit(2);
}
char sql_client[1024] = {0};
sprintf(sql_client,"select id,password from server where id = %d and password = '%s';",msg_accept.id,msg_accept.password);
ret = sqlite3_get_table(db, sql_client, &result, &row, &column, &errmsg);
if(ret != SQLITE_OK)
{
perror("查詢資料庫失敗");
exit(3);
}
int i;
int j;
printf("-------查詢結果如下--------\n");
for(i = 1;i <= row;i++)
{
for(j = 0;j < column;j++)
{
printf("%s|",result[i * column + j]);
}
printf("\n");
}
printf("---------------------------\n");
ret = sqlite3_close(db);
if(ret != SQLITE_OK)
{
perror("關閉資料庫失敗");
exit(4);
}
if(column == 0)
{
printf("你登入的資訊有誤,請重新登入.\n");
msg_send.case_snum = 1;
memset(sendbuff,0,1024);
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
else//登入成功
{
printf("恭喜你登入成功.\n");
if(msg_accept.id == 1000)//管理員登入
{
memset(sendbuff,0,1024);
printf("管理員上線.\n");
msg_send.case_snum = 3;//管理登入成功後傳送到客戶端的指令
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
}
else //普通使用者登入成功
{
memset(sendbuff,0,1024);
printf("普通使用者上線.\n");
msg_send.case_snum = 2;//普通使用者登入成功後傳送到客戶端的指令
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
}
//插入資訊到連結串列
list = insert2(list, msg_accept.id, newfd);
printf("現在線上人物資訊 :\n");
printf_list(list);
printf("線上人數為:%d\n", getcount(list));
while(1)
{
memset(buff,0,1024);
ret = read(newfd,buff,1024);
if(-1 == ret)
{
perror("讀取失敗");
exit(1);
}
memcpy(&msg_accept,buff,sizeof(msg_accept));
switch(msg_accept.case_numnext)
{
case 1://檢視當前人數
{
/*
char str[1024] = {0};
sprintf(str,"當前線上人數為: %d\n",count);
ret = write(newfd,str,1024);
if(-1 == ret)
{
perror("寫入人數失敗");
exit(2);
}
*/
int count = getcount(list);//用連結串列檢視當前的人數
memset(sendbuff ,0 ,1024);
msg_send.id__s = count;//用作id_s臨時記錄下線上的人數
printf("count = %d\n",msg_send.id__s);
msg_send.case_snum = 6;//查詢線上人數
//memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
sleep(1);
linkedlist *h = list;
int temp = 0;
while(h != NULL)
{
msg_send.num_s[temp] = h -> id_l;
temp++;
h = h -> next;
}
msg_send.i_s = temp;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
case 2: //傳送私聊
{
int send_newfd = queryfd(list, msg_accept.id);//查詢私聊人物的FLAG
//是否有此人
// printf("查到的客戶端是: %d\n", send_newfd);
int id_client = queryid(list,newfd);//查詢傳送訊息人物的ID
//printf("id_client = %d\n",id_client);//列印他的ID
if(send_newfd != 0)//有此人
{
printf("客戶端%d 私聊客戶端%d 訊息為 : %s\n",newfd,send_newfd,msg_accept.name);
memset(sendbuff ,0 ,1024);
msg_send.id__s = send_newfd;//用作id_s臨時記錄下客戶端的FLAG
msg_send.case_snum = 4;//查詢有這個ID
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
memset(sendbuff,0,1024);
strcpy(msg_send.name_s,msg_accept.name);
msg_send.case_snum = 7;//用於傳送私聊訊息的指令
msg_send.id__s = id_client;//用於記錄傳送人的ID
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(send_newfd,sendbuff,1024);//傳送給要私聊的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
memset(sendbuff,0,1024);
msg_send.case_snum = 8;//用於發聵訊息傳送成功了指令
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給發起私聊的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
}
else
{
printf("沒有這個ID\n");
memset(sendbuff ,0 ,1024);
msg_send.case_snum = 5;//沒有這個ID
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd ,sendbuff, 1024);
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
}
break;
}
case 3: //傳送群聊
{
int id_client = queryid(list,newfd);//查詢傳送群聊訊息人物的ID
printf("客戶端%d發起了群聊,內容是:%s\n",newfd,msg_accept.name);
int i;
linkedlist *h = list;
//把線上人數都遍歷出來
for(i = 0; i < getcount(list); i++)
{
if(h -> fd_l != newfd)
{
memset(sendbuff, 0, 1024);
strcpy(msg_send.name_s,msg_accept.name);//複製群聊的訊息到伺服器的結構體裡面
msg_send.case_snum = 9;//用於傳送群聊訊息的指令
msg_send.id__s = id_client;//用於記錄傳送人的ID
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(h -> fd_l, sendbuff, 1024);
if(-1 == ret)
{
perror("write");
exit(EXIT_FAILURE);
}
}
h = h -> next;
}
memset(sendbuff,0,1024);
msg_send.case_snum = 10;//用於發聵訊息傳送成功了指令
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給發起群聊的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
case 4: //客戶請求傳送檔案
{
int ret;
int accept_newfd = queryfd(list, msg_accept.id);//查詢檔案要傳送到人物的FLAG
int id_send = queryid(list,newfd);//查詢傳送檔案的ID
printf("客戶端%d請求傳送檔案給客戶端%d,檔名是: %s\n",newfd,accept_newfd,msg_accept.name);
memset(sendbuff,0,1024);
//先把名字發給要接受檔案的人
msg_send.case_snum = 18;
msg_send.id__s = id_send;
strcpy(msg_send.name_s,msg_accept.name);
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(accept_newfd,sendbuff,1024);
if(-1 == ret)
{
perror("寫入失敗\n");
exit(1);
}
//把內容發給要接受檔案的人
while(1)
{
char buffer_file[1024];
memset(buffer_file, 0, 1024);//清空快取
if(recv(newfd, buffer_file, 1024, 0) < 0)
{
perror("接收失敗");
exit(1);
}
printf("內容是 :\n");
printf("%s\n",buffer_file);
if(send(accept_newfd, buffer_file, 1024, 0) < 0)
{
perror("傳送失敗");
exit(1);
}
if(0 == strncmp(buffer_file, "END", 3))
{
break;
}
}
//把傳送成功的訊息發聵給傳送者
memset(sendbuff,1024,0);
msg_send.case_snum = 19;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);
if(-1 == ret)
{
perror("寫入失敗\n");
exit(1);
}
break;
}
case 5: //客戶請求下線
{
printf("客戶端%d請求下線\n",newfd);
list = dellinkedlist(list, newfd);
printf_list(list);
memset(sendbuff,0,1024);
msg_send.case_snum = 11;//用於發聵訊息傳送成功了指令
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給發起請求下線的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
//break;
goto out;
}
case 6://禁言
{
printf("管理員請求禁言,禁言的ID是%d\n",msg_accept.id);
memset(sendbuff, 0, 1024);
int jinyan_newfd = queryfd(list,msg_accept.id);//查詢被禁言人的客戶端
msg_send.case_snum = 12;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(jinyan_newfd,sendbuff,1024);//傳送給被禁言的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
//禁言成功反饋給管理員
msg_send.case_snum = 13;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給被禁言的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
case 7://解禁
{
printf("管理員請求解禁,解禁的ID是%d\n",msg_accept.id);
memset(sendbuff, 0, 1024);
int jiejin_newfd = queryfd(list,msg_accept.id);//查詢被禁言人的客戶端
msg_send.case_snum = 14;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(jiejin_newfd,sendbuff,1024);//傳送給被禁言的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
//解禁成功反饋給管理員
msg_send.case_snum = 15;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給管理員
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
case 8://踢人下線
{
printf("管理員請求踢人,被踢人的ID是%d\n",msg_accept.id);
memset(sendbuff, 0, 1024);
int tiren_newfd = queryfd(list,msg_accept.id);//查詢被踢人的客戶端
msg_send.case_snum = 16;
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(tiren_newfd,sendbuff,1024);//傳送給被踢的人
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
//踢人成功反饋給管理員
msg_send.case_snum = 17;
memset(sendbuff, 0, 1024);
memcpy(sendbuff,&msg_send,sizeof(msg_send));
ret = write(newfd,sendbuff,1024);//傳送給管理員
if(-1 == ret)
{
perror("寫入失敗");
exit(2);
}
break;
}
}
}
break;
}
break;
}
case 3:
{
printf("客戶端%d請求退出\n",newfd);
goto outroom;
}
}//switch
out:
printf("-----------\n");
}//while(1)
outroom:
close(newfd);
}
linkedlist *createlinkedlist()
{
linkedlist *h;
h = NULL;
return h;
}
linkedlist *dellinkedlist(linkedlist *list, int fd)
{
linkedlist *p = list -> next;
linkedlist *h = list;
if(list -> fd_l == fd)
{
free(h);
return list -> next;
}
else
{
while(p -> fd_l != fd)
{
p = p -> next;
h = h -> next;
}
h -> next = p -> next;
free(p);
return list;
}
}
linkedlist *insert2(linkedlist *list, int id, int fd)
{
linkedlist *head, *p;
head = list;
p = (linkedlist *)malloc(sizeof(linkedlist));
if(head == NULL)
{
head = p;
p -> next = NULL;
}
else
{
p -> next = head;
head = p;
}
p -> id_l = id;
p -> fd_l = fd;
return head;
}
int getcount(linkedlist *list)
{
linkedlist *h = list;
int count = 0;
while(h != NULL)
{
count++;
h = h -> next;
}
return count;
}
int queryid(linkedlist *list, int fd)
{
linkedlist *p, *h;
h = list;
while(h != NULL)
{
if(fd == h -> fd_l)
{
return h -> id_l;
}
h = h -> next;
}
}
int queryfd(linkedlist *list, int id)
{
linkedlist *h = list;
while(h != NULL)
{
if(id == h -> id_l)
{
return h -> fd_l;
}
h = h -> next;
}
return 0;
}
void printf_list(linkedlist *list)
{
linkedlist *h = list;
while(h != NULL)
{
printf("線上人物的ID為 :%d FLAG : %d\n", h ->id_l, h -> fd_l);
h = h -> next;
}
printf("\n");
}