Socket網路程式設計 聊天程式 8

2021-09-06 17:17:51 字數 3954 閱讀 2167

上一節已經完成了對使用者的身份驗證了,既然有了驗證,那麼接下來就能對不同的客戶端進行區分了,所以這一節講實現私聊功能。就是通過伺服器對客戶端的資料進行**到特定的使用者上,

實現私聊功能的聊天程式

實現的技術細節是:對客戶端傳送的資料增加乙個標識頭,由於我們處理的是純文字,所以為了講解的方便就把標識頭加到聊天資訊的前面,然後在伺服器中判斷。如果是要在做成產品的話,因為要考慮傳送純文字,,檔案,特定的結構體等等其他非純文字資訊,那麼我們可以對一次聊天資訊,傳送兩次資料,第一次用tcp傳送乙個結構體,該結構體包含接下來要接收的資訊的格式,大小等資訊,然後第二次就傳送真正的資料塊。

回到我們的程式中來吧,我的處理辦法是在伺服器裡判斷第乙個單詞是不是******,如果是就讀取第二個單詞,為使用者名稱,然後根據使用者名稱從fd_c中查詢,看fd_c對應fd_a的socket號碼,然後根據這個fd號碼進行**,而不是進行**。(如果要增加什麼功能,如傳檔案的話那麼,道理一樣,判斷第乙個單詞是不是file,如果是第二個單詞是檔名什麼的,具體就是這樣做的。如果是做有介面的客戶端,就可以進行選擇要聊天的使用者,然後在後台生成******這個標識號了。就對使用者友好一點。)

好了,到了激動人心的時刻了,下面是**講解。

client.c 基本不變

server.c 

...

17 #include //

用於mysql連線

...2425

struct

user26;

3031

int max(int a,int

b)    ...

3738

void print_time(char * ch,time_t *now)

3944

4546

int mysql_check_login(struct

user su)

4793

94//

根據使用者名稱返回該使用者名稱在fd_a中的位置

95//

fd=-1,表示沒有該使用者

//fd>0 正常返回

96int fd_ctoa(char fd_c[32],char *ch)

97107

}108

return

fd;109

}110

111int main(int argc,char *argv)

112243

//fd_copy(recvfd,servfd);

244for(i=0;i//

最大佇列進行判斷,優化的話,可以使用鍊錶

245251

252switch(select(max_recvfd+1,&recvfd,null,null,&timeout))

253274

else

//客戶端傳送資料過來,然後這裡進行**

275289

}290

if(j

291306

else

307312

}313

else

314319

break

;320

}321

else

322324

//其他else就是其他命令了,為了方便就不支援其他命令了

325...

352}

353}

354}

355break

;356

}//end-switch

357}//end-while(1)

358return0;

359 }

照例給個執行時的截圖,提提神。

好了,我們已經完成群聊和私聊的功能了,作為乙個聊天程式實現這兩個基本功能也就差不多啦。

一點小小的補充:

//

上一節忘了說mysql怎麼設定開機啟動了,指令如下,root使用者執行

chkconfig mysqld on

service mysqld start

另乙個知識點的補充,也是今天才注意到的。以前我們每登陸乙個客戶端都會分配乙個檔案描述符fd,而伺服器中對每個連線產生的fd號是從3開始,連乙個就加乙個。而現在分配的id(fd)號是從4開始的不說,還每次增加2。這就奇怪了。

1 [myuser@localhost client-server]$ ./server ser

2username:ser

3success to establish a socket...

4success to bind the socket...

5success to accpet a connection request...

6 >>>>>> 127.0.0.1:54880 join in! id(fd):4

7 加入的時間是:06:39:04

89 客戶端發來的使用者名稱是:user3,密碼:123456

10 查詢的sql:select * from clients where username="

user3

" and password="

123456";

11驗證成功!

12success to accpet a connection request...

13 >>>>>> 127.0.0.1:54881 join in! id(fd):6

14 加入的時間是:06:39:04

1516 客戶端發來的使用者名稱是:user1,密碼:123456

17 查詢的sql:select * from clients where username="

user1

" and password="

123456";

18驗證成功!

19success to accpet a connection request...

20 >>>>>> 127.0.0.1:54882 join in! id(fd):8

21 加入的時間是:06:39:04

2223 客戶端發來的使用者名稱是:user2,密碼:123456

24 查詢的sql:select * from clients where username="

user2

" and password="

123456";

25驗證成功!

26 資料是:user2 06:39:04

就是那幾個大紅色標出來的fd號,連線3個客戶端居然是分配到4,6,8。而不是3,4,5

還好我們的**每次都增加不多,可以很快就知道為什麼?因為有了資料庫的連線。

解釋:檔案描述符0,1,2這三個預設分配給stdin,stdout,stderr,然後接下來就按需分配了。3號是伺服器用於接收客戶端請求而建立的sockfd,在一開始就建立了。4號就是client1了,5號就是client1下連線資料庫而建立的。由於我們的伺服器對每個連線都要有一次訪問資料庫,所以對應單數的那些fd都是用在資料庫連線上了。(什麼是檔案描述符?自己上網查咯)

一些小總結,其實網路程式設計還是很有趣的,了解後就會發現很多看起來很叼的技術,其內部底層還是很簡單的實現的。就我們常常聽到的下面這些技術 防火牆,遠端控制,遠端shell,vpn,內網穿透等等看起來很厲害的技術,都基本上都是使用伺服器,實現一對一的**而已。只不過特定的功能還要靠特定的優化辦法(如一些特定的io操作,演算法,安全性等)處理而已,也就是優化處理速度與安全性。如果是一般的使用,那我們其實都是可以實現的。所以別看乙個小小的聊天程式的乙個私聊功能,其實還是很多高階應用的基礎(麻雀雖小,五臟俱全)。(由於本人技術問題,本博只提供思路,想法和乙個小小的入門級程式。)

參考資料

關於識別符號包頭的詳解: 

socket程式設計之點對點聊天程式

p2psrv.c include include include include include include 解決父程序退出,子程序不退出 include include include include define err exit m do while 0 void handler int ...

黑馬程式設計師 Socket網路程式設計聊天室

windows phone 7手機開發 net培訓 期待與您交流!using system using system.collections.generic using system.componentmodel using system.data using system.drawing usin...

黑馬程式設計師 關於Socket程式設計 網路聊天的總結

windows phone 7手機開發 net培訓 期待與您交流!using system using system.collections.generic using system.componentmodel using system.data using system.drawing usin...