把基本的tutorial 在官網(wǎng)上過(guò)一遍。
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),勉縣企業(yè)網(wǎng)站建設(shè),勉縣品牌網(wǎng)站建設(shè),網(wǎng)站定制,勉縣網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,勉縣網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
然后自己寫(xiě)個(gè)telnet的聊天室, 多人none blocking的就可以了。不用和別人學(xué),別人寫(xiě)的也不一定好。
另外多看看go容易犯的錯(cuò)誤。
我們可以看到 gorilla/websocket中的examples中有一個(gè)聊天室的demo。
我們進(jìn)入該項(xiàng)目可以看到里面有這樣的一些內(nèi)容
按照官方的運(yùn)行方式來(lái)運(yùn)行這個(gè)項(xiàng)目
在瀏覽器中打開(kāi)8080端口,可以看到該項(xiàng)目可以被成功運(yùn)行了。
就是這樣一個(gè)簡(jiǎn)單的demo。
然后我們?nèi)タ匆幌滤木唧w實(shí)現(xiàn)。
在這個(gè)項(xiàng)目中首先定義了一個(gè)hub的結(jié)構(gòu)體:
這個(gè)結(jié)構(gòu)體中,clients代表所有已經(jīng)注冊(cè)的用戶,broadcast管道會(huì)存儲(chǔ)客戶端發(fā)送來(lái)的信息。 register是一個(gè)*Client類型的管道,用于存儲(chǔ)新注冊(cè)的用戶,unregister管道反之。
我們打開(kāi)main.go,main函數(shù)的源碼為:
在這里首先會(huì)新開(kāi)一個(gè)goroutine,去跑hub的run方法,run方法中一個(gè)死循環(huán),不停地去輪詢hub中的內(nèi)容
如果取到了新用戶,就加入到clients中,如果取到了信息,就循環(huán)所有的client,將信息寫(xiě)到client.send中。
我們看到在請(qǐng)求路徑為根的時(shí)候,它會(huì)請(qǐng)求一個(gè)函數(shù),而這個(gè)函數(shù)就是將home.html發(fā)送到客戶端。
而在請(qǐng)求路徑為“/ws”的時(shí)候,他會(huì)執(zhí)行一個(gè)serveWS的函數(shù)。
每當(dāng)一個(gè)新的用戶進(jìn)來(lái)之后,首先將連接升級(jí)為長(zhǎng)連接,然后將當(dāng)前的client寫(xiě)到register中,由hub.run函數(shù)去做處理。然后開(kāi)啟兩個(gè)goroutine,一個(gè)去讀client中發(fā)送來(lái)的數(shù)據(jù),一個(gè)將數(shù)據(jù)寫(xiě)入到所有的client中,去發(fā)送給用戶。
這就是整個(gè)聊天室的實(shí)現(xiàn)原理。
上一節(jié)中,我們?yōu)槊總€(gè)連接都創(chuàng)建了一個(gè)goroutine來(lái)讀取其中的消息,現(xiàn)在我們將這個(gè)讀取消息的方法實(shí)現(xiàn)一下。
我們?cè)赼pplication目錄下新建controllers目錄,并在其中創(chuàng)建一個(gè)MessageController.go文件。
首先我們新建一個(gè)MessageController的結(jié)構(gòu)體,內(nèi)容如下
這個(gè)結(jié)構(gòu)體包括兩個(gè)內(nèi)容,一個(gè)是我們將連接放在數(shù)組之后,返回的索引,另一個(gè)是連接本身.
這個(gè)是具體的方法。
我們首先設(shè)置了一下讀消息的大小、超時(shí)時(shí)間以及超時(shí)后需要的操作。
超時(shí)時(shí)間如果設(shè)置為0,那么就是永不超時(shí)。之前在這里直接寫(xiě)0,被告知需要傳一個(gè)time.Time類型的數(shù)據(jù)。最終谷歌后才得到了這個(gè)值time.Time{}為"0001-01-01 00:00:00 +0000 UTC"。
我們將用戶手法消息的內(nèi)容定義為一個(gè)結(jié)構(gòu)體,然后將用戶的訂閱信息的json通過(guò)json.unmarshal轉(zhuǎn)換成這個(gè)結(jié)構(gòu)體。
之后的switch操作與我們?cè)赟woole中的操作基本雷同,在查詢到login之后,調(diào)用service中 的login方法來(lái)進(jìn)行注冊(cè)。
下一節(jié)中我們?cè)俳榻B具體的注冊(cè)邏輯。
我們?cè)趍ian函數(shù)中,首先初始化配置文件,然后新建http連接。
這個(gè)連接創(chuàng)建之后,監(jiān)聽(tīng)服務(wù)器的9999端口。如果url的路徑后綴為 "/ws",就轉(zhuǎn)發(fā)到ws/ws.go中的IndexHandler方法中。
這個(gè)方法中首先我們創(chuàng)建一個(gè)websocket的Upgrader實(shí)例,然后我們使用Upgrader的upgrade方法來(lái)升級(jí)一下我們的連接為長(zhǎng)連接。
升級(jí)完成之后會(huì)返回一個(gè)*websocket.Conn的連接,我們之后所有的關(guān)于連接的操作,都是基于該conn的。
在該連接完成之后,我們將連接存放到一個(gè)名為Client的map中,以便之后管理更為方便。
之后,我們啟動(dòng)一個(gè)goroutine來(lái)讀取連接中發(fā)送的信息內(nèi)容,再根據(jù)內(nèi)容進(jìn)行相應(yīng)的操作。
這樣:
#include stdlib.h
#include stdio.h
#include errno.h
#include string.h
#include unistd.h
#include netdb.h
#include sys/socket.h
#include netinet/in.h
#include sys/types.h
#include arpa/inet.h
#include pthread.h
#define MAXLINE 100;
void *threadsend(void *vargp);
void *threadrecv(void *vargp);
int main()
{
int *clientfdp;
clientfdp = (int *)malloc(sizeof(int));
*clientfdp = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in serveraddr;
struct hostent *hp;
bzero((char *)serveraddr,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(15636);
serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(connect(*clientfdp,(struct sockaddr *)serveraddr,sizeof(serveraddr)) 0){
? printf("connect error\n");
? exit(1);
}
pthread_t tid1,tid2;
printf("connected\n");
while(1){
pthread_create(tid1,NULL,threadsend,clientfdp);
pthread_create(tid2,NULL,threadrecv,clientfdp);
}
return EXIT_SUCCESS;
}
void *threadsend(void * vargp)
{
//pthread_t tid2;
int connfd = *((int *)vargp);
int idata;
char temp[100];
while(1){
//printf("me: \n ");
fgets(temp,100,stdin);
send(connfd,temp,100,0);
printf("? ? ? ? ? client send OK\n");
}
printf("client send\n");
return NULL;
}
void *threadrecv(void *vargp)
{
char temp[100];
int connfd = *((int *)vargp);
while(1){
int idata = 0;
idata = recv(connfd,temp,100,0);
if(idata 0){
printf("server :\n%s\n",temp);
}
}
return NULL;
}
擴(kuò)展資料:
注意事項(xiàng)
linux下編譯多線程代碼時(shí),shell提示找不到 pthread_create函數(shù),原因是 pthread.h不是linux系統(tǒng)默認(rèn)加載的庫(kù)文件,應(yīng)該使用類似如下gcc命令進(jìn)行編譯:
gcc echoserver.c -lpthread -o echoserver
只要注意 -lpthread參數(shù)就可以了。