網路程式設計下

2021-04-30 18:51:37 字數 4112 閱讀 7242

設定和獲得套介面選項

獲得套介面選項

int getsockopt ( int sockfd, int level, int optname, void * optval, socklen_t *opteln ) 

設定套介面選項:

int setsockopt ( int sockfd, int level, int optname, const void * optval, socklen_t *opteln )  

引數含意

sockfd(套接字): 指向乙個開啟的套介面描述字 

level:(級別): 指定選項**的型別。 

sol_socket: 基本套介面 

ipproto_ip: ipv4套介面 

ipproto_ipv6: ipv6套介面 

ipproto_tcp: tcp套介面 

optname(選項名): 選項名稱 

optval(選項值): 是乙個指向變數的指標 型別:整形,套介面結構, 其他結構型別:linger{}, timeval 

optlen(選項長度) :optval 的大小 

返回值:標誌開啟或關閉某個特徵的二進位制選項

用於設定socket細節

so_reuseaddr 重用位址

當開啟某一埠的程式非正常退出,可能埠仍被占用,第二次執行程式就會報」addr in use」無法使用這一埠

用so_reuseaddr 可以防止這一問題.伺服器的socket,最好用這一選項.

n = socket(af_inet, sock_stream, ipproto_tcp);

val = 1;

setsockopt(n, sol_socket, so_reuseaddr, (char *) &val, sizeof (val));

// some code ...

if ((bind(n, (struct sockaddr *) &sin, sizeof (sin)) < 0)

|| (listen(n, qlen) < 0))

exit(1);

so_broadcast udp廣播選項

一般在傳送udp資料報的時候,希望該socket傳送的資料具有廣播特性

用sendto傳送時,廣播位址可以寫

from.sin_addr.s_addr=inaddr_broadcast;

或是根據ip位址和掩碼算出的子網的廣播位址

int bbroadcast=1; setsockopt(s,sol_socket,so_broadcast,(const char*)&bbroadcast,sizeof(int));

udp廣播例項

#include

#include

#include

#include

#include

#include

#include

#include

int main(int argc, char **argv)

else

printf("create socket./n/r");

/* 設定通訊方式對廣播,即本程式傳送的乙個訊息,網路上所有主機均可以收到 */

yes = 1;

setsockopt(sock, sol_socket, so_broadcast, &yes, sizeof(yes));

/* 唯一變化就是這一點了 */

/* 設定對方位址和埠資訊 */

s_addr.sin_family = af_inet;

if (argv[2])

s_addr.sin_port = htons(atoi(argv[2]));

else

s_addr.sin_port = htons(7838);

//windows

if (argv[1])

s_addr.sin_addr.s_addr = inet_addr(argv[1]);

else

/* 傳送udp訊息 */

addr_len = sizeof(s_addr);

strcpy(buff, "hello i'm here");

len = sendto(sock, buff, strlen(buff), 0,

(struct sockaddr *) &s_addr, addr_len);

if (len < 0)

printf("send success./n/r");

return 0;

}客戶端首先收下定長的結構體,從中讀取檔名和檔案長度.然後連續接收檔案長度的字元,即可將檔案完整接收下來.

由於tcp是不會丟失資料,因此只有二種可能,一種是接收失敗,一種是把檔案完整接收下來.

檔案的阻塞函式

一般檔案讀取函式read,socket的接收函式recv,recvfrom都是阻塞型函式,即沒有資料收到時,整個程式被阻塞這個函式

在伺服器軟體上,經常要接收多個客戶端的資料.如果單純採用recv造成整個程式的阻塞.

一種方法採用多執行緒.

更為常用是採用多路復用函式select來同時控制多個socket/file 描述符.

select多路復用

select系統呼叫是用來讓我們的程式監視多個檔案控制代碼(file descrīptor)的狀態變化的。程式會停在select這裡等待,直到被監視的檔案控制代碼有某乙個或多個發生了狀態改變。

普通檔案讀寫

socket的收發

裝置檔案的收發

fd_set資料結構

select主要操作fd_set的資料結構.fd_set是乙個檔案描述符的向量陣列

大體上可以把fd_set看成乙個只有32項的整數陣列.

每乙個socket或fd都是fd_set中的一項,

一般採用一組巨集來操作fd_set

void fd_set(int fd,fd_set *fdset)

void fd_clr(int fd,fd_set *fdset)

fd_clr將fd從fdset裡面清除 

void fd_zero(fd_set *fdset)

fd_zero從fdset中清除所有的檔案描述符 

int fd_isset(int fd,fd_set *fdset)

fd_isset判斷fd是否在fdset集合中

typedef struct fd_set     

select定義

int select(int max_fd, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);

其中max_fd為我們要監聽的套接字中值最大的乙個,同時在呼叫select是要將其加1,

readfd即為我們監聽的要進行讀操作的套接字連線集合,

第三個引數是我們監聽的要進行寫操作的套接字連線集合,

第四個引數用於異常,而最後乙個引數可以用來設定超時,這裡同樣使用了struct timeval結構,

當有檔案被寫時,返回乙個大於0值,出錯返回乙個負數,等於表示在timeout的時間,沒有任何讀寫,select是超時返回的

select()的使用

select同時監控多個啟用的socket(最大值一般為1024)

當相應的socket上有資料接收時,select將其值寫入readfd值中.並返回乙個大於0值.

這樣通過fd_isset可以查出是哪乙個socket被讀寫.因為只有乙個阻塞點.大大提高程式的效能

因為帶有超時機制,也能防止長時間阻塞導致程式無法響應的後果

select也能處理一般的檔案或裝置檔案,如把標準輸入或普通檔案加入到監控的集合中

select例項

int main()     else if(ret == 0)

else

} select的socket下使用流程

select 的使用是固定的流程

socket(...);   bind(...);   listen(...);              while(1)                   else

}   

練習多個檔名可由配置檔案或直接寫在原始碼裡,請將廣播和聊天伺服器**移植到linux上

windows 下的網路程式設計

用簡單的 和演示說明了winsocket的使用一般必要步驟。先看看程式執行的效果吧 最上面的乙個視窗為服務端,下面的視窗為客戶端,服務端的主迴圈負責接收資料。如果客戶端輸出 exit 字串的話,則服務端和客戶端程式終止。這個示例主要是通過簡單的 讓初學者了解到wsa winsocketapi 的啟動...

windows下的網路程式設計

windows下的網路程式設計 做過windows網路程式設計的人都知道,微軟的mfc把複雜的winsock api函式封裝到類裡,這使得編寫網路應用程式更容易。即windows既提供上層的網路api函式也提供底層的api函式。1 對於採用上層的api函式而言 若採用csocket類定義乙個物件ob...

VS下C 網路程式設計

提供了強制資料立即傳送的操作指令 push,tcp軟體收到該操作指令後,就立即將本段資料傳送出去,而不必等待傳送緩衝區滿 include pragma comment lib,ws2 32.lib int tmain int argc,tchar argv socket socket socksrv...