網絡編程中參數的獲得與設置

取得本地主機名:

int gethostname(char *hostname, size_t size);

獲得主機名存到hostname中。

 


取得本地的信息:

int getsockname(int sockfd, struct sockaddr *addr, int *addrlen);

addr存有返回的主機信息。

示例:

struct sockaddr_in sa;

int len = sizeof(sa);

getpeername(sockfd, (struct sockaddr *)&sa, &len);

printf("本地IP:%s", inet_ntoa(sa.sin_addr));

 

 

取得對方主機的信息:

int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);

addr存有返回的主機信息。

示例:

struct sockaddr_in sa;

int len = sizeof(sa);

getpeername(sockfd, (struct sockaddr *)&sa, &len);

printf("對方IP:%s", inet_ntoa(sa.sin_addr));

 


獲得DNS信息:

struct hostent *gethostbyname(const char *name);

struct hostent *gethostbyaddr(const char *addr, int len, int type);

返回了一個指向struct hostent的指針,struct hostent定義如下:

struct hostent {

char *h_name; /* official name of host */

char **h_aliases; /* alias list */

int h_addrtype; /* host address type */

int h_length; /* length of address */

char **h_addr_list; /* list of addresses */

};

#define h_addr h_addr_list[0] /* for backward compatibility */

對於如何獲得DNS信息,將在後面的程序片斷中詳細講解。

DNS操作時的錯誤處理與普通程序不同,gethostbyname通過設置h_errno代表出錯號,對應的錯誤函數有hstrerror()和herror(),分別對應於strerror()和perror()這兩個普通的錯誤函數。


獲得或改變socket屬性

int getsockopt(int sockfd, int level, int name, char *value, int *optlen);

int setsockopt(int sockfd, int level, int name, char *value, int *optlen);

對於socket編程,level一般爲常數SOL_SOCKET

name屬性類型,value屬性參數,optlen屬性內存塊的長度

常用的有:

SO_RCVTIMEO,SO_SNDTIMEO:獲得或設置socket發送/接收的timeout。

SO_SNDBUF,SO_RCVBUF:獲得或設置socket發送/接收的buffer大小。

SO_BROADCAST:獲得或設置socket狀況,使之可以廣播發送數據報。(只能用於UDP方式)。

SO_REUSEADDR:設置該socket綁定的端口可以被重用。

注意:在Linux系統中,如果一個socket綁定了某個端口,該socket正常關閉或程序退出後,在一段時間內該端口依然保持被綁定的狀態,其他程序(或者重新啓動的原程序)無法綁定該端口。可以通過調用以下語句避免該問題:

opt = 1;
len = sizeof(opt);
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,&len);

 


獲得或改變socket的I/O屬性:

int ioctl(int sockfd,long cmd,unsigned long* argp);

cmd屬性類型,argp屬性的參數。

常用的有:

FIONREAD,返回socket緩衝區中未讀數據的字節數

FIONBIO,argp爲零時爲阻塞模式,非零時爲非阻塞模式

SIOCATMARK ,判斷是否有未讀的帶外數據(僅用於TCP協議),返回true或false

 

int fcntl(int fd, int cmd, long arg);

F_SETFL,arp爲O_NONBLOCK時進入非阻塞模式,爲0時進入阻塞模式。

F_GETFL,獲得屬性。

 

初始化sock連接符:

int socket(int domain, int type, int protocol);

函數返回socket描述符,返回-1表示出錯

domain參數只能取AF_INET, protocol參數一般取0

應用示例:

TCP方式:sockfd = socket(AF_INET,SOCK_STREAM,0);

UDP方式:sockfd =socket(AF_INET, SOCK_DGRAM,0);

 


綁定端口:

int bind(int sockfd, struct sockaddr *sa, int addrlen);

函數返回-1表示出錯,最常見的錯誤是該端口已經被其他程序綁定。

需要注意的一點:在Linux系統中,1024以下的端口只有擁有root權限的程序才能綁定。

 


連接網絡(用於TCP方式):

int connect(int sockfd, struct sockaddr *servaddr, int addrlen);

函數返回-1表示出錯,可能是連接超時或無法訪問。返回0表示連接成功,可以通過sockfd傳輸數據了。

 


監聽端口(用於TCP方式):

int listen(int sockfd, int queue_length);

需要在此前調用bind()函數將sockfd綁定到一個端口上,否則由系統指定一個隨機的端口。

接收隊列:一個新的Client的連接請求先被放在接收隊列中,直到Server程序調用accept函數接受連接請求。

第二個參數queue_length,指的就是接收隊列的長度 也就是在Server程序調用accept函數之前最大允許的連接請求數,多餘的連接請求將被拒絕。

 


響應連接請求(用於TCP方式):

int accept(int sockfd,struct sockaddr *addr,int *addrlen);

accept()函數將響應連接請求,建立連接併產生一個新的socket描述符來描述該連接,該連接用來與特定的Client交換信息。

函數返回新的連接的socket描述符,錯誤返回-1

addr將在函數調用後被填入連接對方的地址信息,如對方的IP、端口等。

addrlen作爲參數表示addr內存區的大小,在函數返回後將被填入返回的addr結構的大小。

accept缺省是阻塞函數,阻塞直到有連接請求

應用示例:

struct sockaddr_in their_addr; /* 用於存儲連接對方的地址信息*/
int sin_size = sizeof(struct sockaddr_in);

… …(依次調用socket(), bind(), listen()等函數)

new_fd = accept(sockfd, &their_addr, &sin_size);
printf(”對方地址: %s/n", inet_ntoa(their_addr.sin_addr));

… …

 


關閉socket連接:

int close(int sockfd);

關閉連接將中斷對該socket的讀寫操作。

關閉用於listen()的socket描述符將禁止其他Client的連接請求。

 


部分關閉socket連接:

int shutdown(int sockfd, int how);

Shutdown()函數可以單方面的中斷連接,即禁止某個方向的信息傳遞。

參數how:

0 - 禁止接收信息
1 - 禁止發送信息
2 - 接收和發送都被禁止,與close()函數效果相同

 


socket輪詢選擇:

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

應用於多路同步I/O模式(將在同步工作模式中詳細講解)

 FD_ZERO(*set) 清空socket集合 
 FD_SET(s, *set) 將s加入socket集合 
 FD_CLR(s, *set) 從socket集合去掉s 
 FD_ISSET(s, *set) 判斷s是否在socket集合中 


    常數FD_SETSIZE:集合元素的最多個數

 

等待選擇機制:

int poll(struct pollfd *ufds, unsigned int nfds, int timeout);

是select機制的一個變種,應用於多路同步I/O模式(將在同步工作模式中詳細講解)

ufds是pollfd結構的數組,數組元素個數爲nfds。

     struct pollfd {
           int fd;           /* file descriptor */
           short events;     /* requested events */
           short revents;    /* returned events */
       };
 

 

接收/發送消息:

TCP方式:

int send(int s, const void *buf, int len, int flags);

int recv(int s, void *buf, int len, int flags);

函數返回實際發送/接收的字節數,返回-1表示出錯,需要關閉此連接。

函數缺省是阻塞函數,直到發送/接收完畢或出錯

注意:如果send函數返回值與參數len不相等,則剩餘的未發送信息需要再次發送

 

UDP方式:

int sendto(int s, const void *buf, int len, int flags, const struct sockaddr *to, int tolen);

int recvfrom(int s,void *buf, int len, int flags, struct sockaddr *from, int *fromlen);

與TCP方式的區別:

需要指定發送/接收數據的對方(第五個參數to/from)

函數返回實際發送/接收的字節數,返回-1表示出錯。

函數缺省是阻塞函數,直到發送/接收完畢或出錯

注意:如果send函數返回值與參數len不相等,則剩餘的未發送信息需要再次發送

 

基於消息的方式:

int sendmsg(int s, const struct msghdr *msg, int flags);

int recvmsg(int s, struct msghdr *msg, int flags);

發送/接收一個消息,消息使用如下數據結構:

struct msghdr {

void * msg_name; /* optional address */

socklen_t msg_namelen; /* size of address */

struct iovec * msg_iov; /* scatter/gather array */

size_t msg_iovlen; /* # elements in msg_iov */

void * msg_control; /* ancillary data, see below */

socklen_t msg_controllen; /* ancillary data buffer len */

int msg_flags; /* flags on received message */

};

這種方式可以使用面向連接和無連接兩種方式,靈活性較大,但不太常用,將在後面的程序示例(網絡仿真設備)中解釋工作流程。

 

標誌位:

上面這六個發送/接收函數均有一個參數flags,用來指明數據發送/接收的標誌,常用的標誌主要有:

MSG_PEEK 對數據接收函數有效,表示讀出網絡數據後不清除已讀的數據

MSG_WAITALL 對數據接收函數有效,表示一直執行直到buf讀滿、socket出錯或者程序收到信號。

MSG_DONTWAIT 對數據發送函數有效,表示不阻塞等待數據發送完後返回,而是直接返回。(只對非阻塞socket有效)

MSG_NOSIGNAL 對發送接收函數有效,表示在對方關閉連接後出錯但不發送SIGPIPE信號給程序。

MSG_OOB 對發送接收都有效,表示讀/寫帶外數據(out-of-band data)

 


http://263.aka.org.cn/Lectures/002/Lecture-2.1.8/Lecture-2.1.8/new_page_31.htm
帶外數據實例圖

 


IP地址轉換函數:

unsigned long inet_addr (const char *cp);

inet_addr將一個點分十進制IP地址字符串轉換成32位數字表示的IP地址(網絡字節順序)。

   

char* inet_ntoa (struct in_addr in);

inet_ntoa將一個32位數字表示的IP地址轉換成點分十進制IP地址字符串。

 

這兩個函數互爲反函數

   

 

字節順序轉換

htons()--"Host to Network Short"

htonl()--"Host to Network Long"

ntohs()--"Network to Host Short"

ntohl()--"Network to Host Long"

發佈了48 篇原創文章 · 獲贊 3 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章