socket03 小變形,點對點通訊聊天

2021-07-11 12:18:10 字數 4607 閱讀 6298

回顧一下上篇中提到的幾個常用的結構和函式:

//最常用的ipv4的sockaddr

struct sockaddr_in 總共是16個位元組

uint16_t htons(uint16_t hostshort); //轉port

uint32_t htonl(uint32_t hostlong); //轉ip

//其餘兩個反過來即是

//將cp(點分十進位制ip)轉換成二進位制數字(in_addr型),再存放到inp中,一般我們不使用它

int inet_aton(const

char* cp,struct in_addr* inp);

//將cp轉換成二進位制數字(in_addr)

int_addr_t inet_addr(const

char* cp);

//將in_addr型轉換為點分十進位制ip

char* inet_ntoa(struct in_addr in);

回看了下這些結構和函式,咱來稍微改一下上次的程式,模擬乙個點對點的聊天通訊

這裡**分成一段一段來寫,之後整合即可,從下面開始標號:

/* 這一段是後續加進去的,先不看

void handler(int sig)

*///1.首先常用的是初始化server端的套接字,監聽

int main(void)

初始化工作完成之後,就是server端的對請求的操作了,繼續寫server.c:

//2.繼續上面的**

//建立乙個對等方的位址,之後要用它來識別客戶端

struct sockaddr_in peeraddr;

socklen_t peerlen = sizeof(peeraddr);

int conn;

//從已完成連線佇列返回第乙個連線,如果已完成的連線隊列為空,則阻塞在這裡,意思就是沒人連的時候server就卡在這裡不執行下面的**了

//如果有連線,則這函式將返回的資訊都儲存在了peeraddr中了

if((conn = accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen)) < 0)

err_exit("accept");

printf("the client's ip address is : %s , port is : %d \n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));

//如果上面的accept不阻塞,也就是返回了連線,那就開始處理這個連線

pid_t pid;

pid = fork();

if(pid == -1)

err_exit("fork");

if(pid == 0) //建立子程序成功,進入

; //只有當寫入的時候才會「傳送」,不然阻塞在這裡

while(fgets(sendbuf,sizeof(sendbuf),stdin) != null)

printf("clild closed\n");

exit(exit_success);

}else

fputs(recvbuf,stdout); //將收到的資訊列印到標準輸出

}printf("parent close!\n");

kill(pid,sigusr1);

exit(exit_success);

}return

0;

總結一下server端(這裡其實可以叫對等端了,因為是兩者之間的通訊)的過程:

1.首先建立套接字,設定套接字,bind本機位址,監聽它

2.之後將建立好的套接字阻塞在接受對等端的連線,一旦有連線進來,列印對方的ip和port資訊,並且fork乙個子程序來處理連線

3.fork成功,表明子程序和對等方的socket連線上了,在子程序中專門處理要傳送資料的情況(這裡處理好了server端向client端傳送資料的單向聊天)

4.子程序完了,看回父程序,它執行完那個accept就沒事幹了,那再給它分配乙個接受client反傳來的訊息這個工作,執行乙個read操作,如果讀到的ret內容為0—說明已經關閉連線,有內容的話就列印到標準輸出(這裡server能接收資料了)

上面的過程完了,也就說明server端可以接髮資料了。

下面看我們的client端:

//client端的初始化套接字和server端基本上完全一樣,不同的是將ip位址指定為127.0.0.1,因為我們是單機操作,還有它是主動發起連線方,不需要繫結和監聽

/* 這一段是後續加進去的

void handler(int sig)

*/int sock;

if((sock = socket(pf_inet,sock_stream,ipproto_tcp))<0)

err_exit("socket");

struct sockaddr_in servaddr;

memset(&servaddr , 0 , sizeof(servaddr));

servaddr.sin_family = af_inet;

servaddr.sin_port = htons(5188);

//上面的都一樣

servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

//發起連線請求

if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)

err_exxit("connect");

//fork子程序來接受資料

pid_t pid;

pid = fork();

if(pid == -1)

err_exit("fork");

if(pid == 0)

; while(1)

fputs(recvbuf,stdout);

}close(sock);

kill(getppid(),sigusr1);

}else

; while(fgets(sendbuf,sizeof(sendbuf),stdin) != null)

close(sock);

}return

0;

總結一下client端的流程:

1.建立套接字sock,初始化位址(咱們要請求的server端的位址)

2.使用connect向server的位址傳送連線請求

3.fork乙個子程序出來處理接受資料,因為client是主動請求端,它連上之後必然首先是client先傳送訊息,所以父程序處理傳送,子程序處理接受

4.父子程序是同時執行的,可以同時響應訊息,而父程序在你不操作client端時候不走了,也就是阻塞在了fgets這裡,同時只有當有資料到來的時候才執行子程序read,阻塞在了read這裡。

注意,還有乙個地方我們沒說道,就是在server和client某一端斷開連線,應該是互相都應該斷開(可是我們上面這個程式沒有),我們使用了乙個捕捉訊號量的方法來處理這種情況

在某個程序退出的時候,它會返回乙個訊號量給當前程序,我們需要使用乙個訊號量來獲取到這個訊號量,為了好觀察,我們將它列印出來

執行上面的函式

void handler(int sig)

退出程式,按照之後的邏輯:

如果是server主動關閉(那程式自動退出了),那麼client會收到ret == 0,知道對面已經不來資料了,break跳出while(1),下面就是close(sock),傳送乙個close給server端,同時kill子程序的pid

如果是client端主動關閉(同上,程式退出),那麼server端會得到乙個ret == 0,知道對面斷開連線,break跳出while(1),kill掉父程序pid,server程式再退出。

到這裡就得到乙個較為完整的點對點的聊天程式。

最後加上需要的標頭檔案和err_exit(char*)函式即可,前篇裡面有。

程式執行的效果圖如下,這是由client先發起的聊天:

客戶端先關閉的話:

為什麼圖中會出現這樣的情況?程序結束了還列印recv a sig = 10到螢幕上?

因為這裡是先kill的父程序,然後再退出程式,而當時的子程序並沒有結束,在它收到sigusr1之後,跳到handler函式中,列印錯誤sig(到標準輸出上),之後才退出 子程序程式。

總結:

還需要完善,理清楚程式的邏輯很重要

有什麼錯誤還希望指出,**經過測試可用。

css3變形及動畫的小知識點

1.變形 旋轉rotate div class div span 我不想旋轉 span div div 2.變形 扭曲skew 扭曲skew 函式能夠讓元素傾斜顯示。它可以將乙個物件以其中心位置圍繞著x軸和y軸按照一定的角度傾斜。這與rotate 函式的旋轉不同,rotate 函式只是旋轉,而不會改...

對遞迴函式的一點小理解

對於遞迴函式,大家都很熟悉了,對於解析一些複雜資料結構方面,能夠使 非常簡潔,明了。從我的理解來說,遞迴函式一般效率比較低,而且自身特點導致的限制也不少 1.效率低 乙個非常簡單的例子數數吧,從1數到1m。對於迴圈實現的 遞迴實現 對於迴圈實現,函式相當於 對於遞迴實現,相當於 對於第一種實現,不需...

大學生戀愛交友軟體03(小幸運) 痛點分析

補充 其實我們之前的分析還忽略了一類人群,那便是內向的學生群體。這類人通常宅在寢室裡,不願意與過多的人交流接觸,但是這類人依然有愛情的需求,所以這就需要軟體每天給他們推送一些異性物件,這些推送資訊包括異性的 年齡,愛好,專業等等,然後他們可以通過這些推送資訊選擇適合自己的另一半。其實在第一篇 需求調...