青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 297,  comments - 15,  trackbacks - 0
本文介紹Linux系統(tǒng)網(wǎng)絡(luò)編程的內(nèi)容,如套接口的概念與使用、網(wǎng)絡(luò)編程的結(jié)構(gòu)等。
1 什么是套接口
簡(jiǎn)單地說(shuō),套接口就是一種使用UNIX系統(tǒng)中的文件描述符和系統(tǒng)進(jìn)程通信的一種方法。
因?yàn)樵赨NIX系統(tǒng)中,所有的I/O操作都是通過(guò)讀寫(xiě)文件描述符而產(chǎn)生的。文件描述符就是
一個(gè)和打開(kāi)的文件相關(guān)連的整數(shù)。但文件可以是一個(gè)網(wǎng)絡(luò)連接、一個(gè)FIFO、一個(gè)管道、一個(gè)
終端、一個(gè)真正存儲(chǔ)在磁盤(pán)上的文件或者UNIX系統(tǒng)中的任何其他的東西。所以,如果你希望
通過(guò)Internet和其他的程序進(jìn)行通信,你只有通過(guò)文件描述符。
使用系統(tǒng)調(diào)用socket(),你可以得到socket()描述符。然后你可以使用send() 和recv()調(diào)用而
與其他的程序通信。你也可以使用一般的文件操作來(lái)調(diào)用read() 和write()而與其他的程序進(jìn)行
通信,但send() 和recv()調(diào)用可以提供一種更好的數(shù)據(jù)通信的控制手段。下面我們討論Internet
套接口的使用方法。
2 兩種類(lèi)型的Internet套接口
有兩種最常用的Internet 套接口,“數(shù)據(jù)流套接口”和“數(shù)據(jù)報(bào)套接口”,以后我們用
“SOCK_STREAM” 和“SOCK_DGRAM”分別代表上面兩種套接口。數(shù)據(jù)報(bào)套接口有時(shí)也
叫做“無(wú)連接的套接口”。
數(shù)據(jù)流套接口是可靠的雙向連接的通信數(shù)據(jù)流。如果你在套接口中以“ 1, 2”的順序放入
兩個(gè)數(shù)據(jù),它們?cè)诹硪欢艘矔?huì)以“1, 2”的順序到達(dá)。它們也可以被認(rèn)為是無(wú)錯(cuò)誤的傳輸。
經(jīng)常使用的telnet應(yīng)用程序就是使用數(shù)據(jù)流套接口的一個(gè)例子。使用HTTP的WWW瀏覽器
也使用數(shù)據(jù)流套接口來(lái)讀取網(wǎng)頁(yè)。事實(shí)上,如果你使用telnet 登錄到一個(gè)WWW站點(diǎn)的8 0端口,
然后鍵入“GET 網(wǎng)頁(yè)名”,你將可以得到這個(gè)HTML頁(yè)。數(shù)據(jù)流套接口使用TCP得到這種高質(zhì)
量的數(shù)據(jù)傳輸。數(shù)據(jù)報(bào)套接口使用UDP,所以數(shù)據(jù)報(bào)的順序是沒(méi)有保障的。數(shù)據(jù)報(bào)是按一種應(yīng)
答的方式進(jìn)行數(shù)據(jù)傳輸?shù)摹?br>3 網(wǎng)絡(luò)協(xié)議分層
由于網(wǎng)絡(luò)中的協(xié)議是分層的,所以上層的協(xié)議是依賴(lài)于下一層所提供的服務(wù)的。也就是說(shuō),
你可以在不同的物理網(wǎng)絡(luò)中使用同樣的套接口程序,因?yàn)橄聦拥膮f(xié)議對(duì)你來(lái)說(shuō)是透明的。
UNIX系統(tǒng)中的網(wǎng)絡(luò)協(xié)議是這樣分層的:
• 應(yīng)用層( telnet、ftp等)。
• 主機(jī)到主機(jī)傳輸層( TCP、UDP )。
• Internet層( IP和路由)。
• 網(wǎng)絡(luò)訪問(wèn)層(網(wǎng)絡(luò)、數(shù)據(jù)鏈路和物理層)。
4 數(shù)據(jù)結(jié)構(gòu)
下面我們要討論使用套接口編寫(xiě)程序可能要用到的數(shù)據(jù)結(jié)構(gòu)。
首先是套接口描述符。一個(gè)套接口描述符只是一個(gè)整型的數(shù)值: i n t。
第一個(gè)數(shù)據(jù)結(jié)構(gòu)是struct sockaddr,這個(gè)數(shù)據(jù)結(jié)構(gòu)中保存著套接口的地址信息。
struct sockaddr {
   unsigned short sa_family;    /* address family, AF_xxx */
   char sa_data[14];               /* 14 bytes of protocol address */
} ;
sa_family 中可以是其他的很多值,但在這里我們把它賦值為“ A F _ I N E T”。s a _ d a t a包括一
個(gè)目的地址和一個(gè)端口地址。
你也可以使用另一個(gè)數(shù)據(jù)結(jié)構(gòu)s o c k a d d r _ i n,如下所示:
struct sockaddr_in {
   short int sin_family;                   /* Address family */
   unsigned short int sin_port;       /* Port number */
   struct in_addr sin_addr;           /* Internet address */
   unsigned char sin_zero[8];       /* Same size as struct sockaddr */
} ;
這個(gè)數(shù)據(jù)結(jié)構(gòu)使得使用其中的各個(gè)元素更為方便。要注意的是sin_zero應(yīng)該使用bzero() 或
者memset()而設(shè)置為全0。另外,一個(gè)指向sockaddr_in數(shù)據(jù)結(jié)構(gòu)的指針可以投射到一個(gè)指向數(shù)
據(jù)結(jié)構(gòu)sockaddr的指針,反之亦然。
5 IP地址和如何使用IP地址
有一系列的程序可以使你處理I P地址。
首先,你可以使用inet_addr()程序把諸如“132.241.5.10”形式的IP地址轉(zhuǎn)化為無(wú)符號(hào)的整
型數(shù)。
ina.sin_addr.s_addr = inet_addr("132.241.5.10");
如果出錯(cuò),inet_addr()程序?qū)⒎祷? 1。
也可以調(diào)用inet_ntoa()把地址轉(zhuǎn)換成數(shù)字和句點(diǎn)的形式:
printf ("%s", inet_ntoa (ina.sin_addr));
這將會(huì)打印出I P地址。它返回的是一個(gè)指向字符串的指針。
5.1 socket()
我們使用系統(tǒng)調(diào)用socket()來(lái)獲得文件描述符:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
第一個(gè)參數(shù)domain設(shè)置為“AF_INET”。第二個(gè)參數(shù)是套接口的類(lèi)型:SOCK_STREAM 或
SOCK_DGRAM。第三個(gè)參數(shù)設(shè)置為0。
系統(tǒng)調(diào)用socket()只返回一個(gè)套接口描述符,如果出錯(cuò),則返回- 1。
5.2 bind()
一旦你有了一個(gè)套接口以后,下一步就是把套接口綁定到本地計(jì)算機(jī)的某一個(gè)端口上。但
如果你只想使用connect()則無(wú)此必要。
下面是系統(tǒng)調(diào)用bind()的使用方法:
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
第一個(gè)參數(shù)sockfd 是由socket()調(diào)用返回的套接口文件描述符。第二個(gè)參數(shù)my_addr 是指向
數(shù)據(jù)結(jié)構(gòu)sockaddr的指針。數(shù)據(jù)結(jié)構(gòu)sockaddr中包括了關(guān)于你的地址、端口和I P地址的信息。
第三個(gè)參數(shù)addrlen可以設(shè)置成sizeof(struct sockaddr)。
下面是一個(gè)例子:
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MYPORT 3490
m a i n ( )
{
int sockfd;
struct sockaddr_in my_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* do some error checking! */
m y _ a d d r.sin_family = AF_INET; /* host byte order */
m y _ a d d r.sin_port = htons(MYPORT); /* short, network byte order */
m y _ a d d r. s i n _ a d d r.s_addr = inet_addr("132.241.5.10");
b z e r o ( & ( m y _ a d d r.sin_zero), 8); /* zero the rest of the struct */
/* don't forget your error checking for bind(): */
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
如果出錯(cuò),bind() 也返回- 1。
如果你使用connect()系統(tǒng)調(diào)用,那么你不必知道你使用的端口號(hào)。當(dāng)你調(diào)用connect()時(shí),
它檢查套接口是否已經(jīng)綁定,如果沒(méi)有,它將會(huì)分配一個(gè)空閑的端口。
5.3 connect()
系統(tǒng)調(diào)用connect()的用法如下:
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
第一個(gè)參數(shù)還是套接口文件描述符,它是由系統(tǒng)調(diào)用socket()返回的。第二個(gè)參數(shù)是
serv_addr是指向數(shù)據(jù)結(jié)構(gòu)sockaddr的指針,其中包括目的端口和I P地址。第三個(gè)參數(shù)可以使用
sizeof(struct sockaddr)而獲得。下面是一個(gè)例子:
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#define DEST_IP "132.241.5.10"
#define DEST_PORT 23
main()
{
int sockfd;
struct sockaddr_in dest_addr; /* will hold the destination addr */
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* do some error checking! */
d e s t _ a d d r.sin_family = AF_INET; /* host byte order */
d e s t _ a d d r.sin_port = htons(DEST_PORT); /* short, network byte order */
d e s t _ a d d r. s i n _ a d d r.s_addr = inet_addr(DEST_IP);
b z e r o ( & ( d e s t _ a d d r.sin_zero), 8); /* zero the rest of the struct */
/* don't forget to error check the connect()! */
connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
同樣,如果出錯(cuò), c o n n e c t ( )將會(huì)返回- 1。
5.4 listen()
如果你希望不連接到遠(yuǎn)程的主機(jī),也就是說(shuō)你希望等待一個(gè)進(jìn)入的連接請(qǐng)求,然后再處理
它們。這樣,你通過(guò)首先調(diào)用l i s t e n ( ),然后再調(diào)用a c c e p t ( )來(lái)實(shí)現(xiàn)。
系統(tǒng)調(diào)用l i s t e n ( )的形式如下:
int listen(int sockfd, int backlog);
第一個(gè)參數(shù)是系統(tǒng)調(diào)用s o c k e t ( )返回的套接口文件描述符。第二個(gè)參數(shù)是進(jìn)入隊(duì)列中允許
的連接的個(gè)數(shù)。進(jìn)入的連接請(qǐng)求在使用系統(tǒng)調(diào)用a c c e p t ( )應(yīng)答之前要在進(jìn)入隊(duì)列中等待。這個(gè)
值是隊(duì)列中最多可以擁有的請(qǐng)求的個(gè)數(shù)。大多數(shù)系統(tǒng)的缺省設(shè)置為2 0。你可以設(shè)置為5或者1 0。
當(dāng)出錯(cuò)時(shí),l i s t e n ( )將會(huì)返回- 1值。
當(dāng)然,在使用系統(tǒng)調(diào)用l i s t e n ( )之前,我們需要調(diào)用b i n d ( )綁定到需要的端口,否則系統(tǒng)內(nèi)
核將會(huì)讓我們監(jiān)聽(tīng)一個(gè)隨機(jī)的端口。所以,如果你希望監(jiān)聽(tīng)一個(gè)端口,下面是應(yīng)該使用的系統(tǒng)
調(diào)用的順序:
s o c k e t ( ) ;
b i n d ( ) ;
l i s t e n ( ) ;
/* accept() goes here */
5.5 accept()
系統(tǒng)調(diào)用a c c e p t ( )比較起來(lái)有點(diǎn)復(fù)雜。在遠(yuǎn)程的主機(jī)可能試圖使用c o n n e c t ( )連接你使用
l i s t e n ( )正在監(jiān)聽(tīng)的端口。但此連接將會(huì)在隊(duì)列中等待,直到使用a c c e p t ( )處理它。調(diào)用a c c e p t ( )
之后,將會(huì)返回一個(gè)全新的套接口文件描述符來(lái)處理這個(gè)單個(gè)的連接。這樣,對(duì)于同一個(gè)連接
來(lái)說(shuō),你就有了兩個(gè)文件描述符。原先的一個(gè)文件描述符正在監(jiān)聽(tīng)你指定的端口,新的文件描
述符可以用來(lái)調(diào)用s e n d ( )和r e c v ( )。
調(diào)用的例子如下:
#include <sys/socket.h>
int accept(int sockfd, void *addr, int *addrlen);
第一個(gè)參數(shù)是正在監(jiān)聽(tīng)端口的套接口文件描述符。第二個(gè)參數(shù)a d d r是指向本地的數(shù)據(jù)結(jié)構(gòu)
s o c k a d d r _ i n的指針。調(diào)用c o n n e c t ( )中的信息將存儲(chǔ)在這里。通過(guò)它你可以了解哪個(gè)主機(jī)在哪個(gè)
端口呼叫你。第三個(gè)參數(shù)同樣可以使用sizeof(struct sockaddr_in)來(lái)獲得。
如果出錯(cuò),a c c e p t ( )也將返回- 1。下面是一個(gè)簡(jiǎn)單的例子:
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MYPORT 3490 /* the port users will be connecting to */
#define BACKLOG 10 /* how many pending connections queue will hold */
m a i n ( )
{
int sockfd, new_fd; /* listen on sock_fd, new connection on new_fd */
struct sockaddr_in my_addr; /* my address information */
struct sockaddr_in their_addr; /* connector's address information */
int sin_size;
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* do some error checking! */
m y _ a d d r.sin_family = AF_INET; /* host byte order */
m y _ a d d r.sin_port = htons(MYPORT); /* short, network byte order */
m y _ a d d r. s i n _ a d d r.s_addr = INADDR_ANY; /* auto-fill with my IP */
b z e r o ( & ( m y _ a d d r.sin_zero), 8); /* zero the rest of the struct */
/* don't forget your error checking for these calls: */
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
listen(sockfd, BACKLOG);
sin_size = sizeof(struct sockaddr_in);
new_fd = accept(sockfd, &their_addr, &sin_size);
下面,我們將可以使用新創(chuàng)建的套接口文件描述符n e w _ f d來(lái)調(diào)用s e n d ( )和r e c v ( )。
5.6 send() 和recv()
系統(tǒng)調(diào)用s e n d ( )的用法如下:
int send(int sockfd, const void *msg, int len, int flags);
第一個(gè)參數(shù)是你希望給發(fā)送數(shù)據(jù)的套接口文件描述符。它可以是你通過(guò)s o c k e t ( )系統(tǒng)調(diào)用
返回的,也可以是通過(guò)a c c e p t ( )系統(tǒng)調(diào)用得到的。第二個(gè)參數(shù)是指向你希望發(fā)送的數(shù)據(jù)的指針。
第三個(gè)參數(shù)是數(shù)據(jù)的字節(jié)長(zhǎng)度。第四個(gè)參數(shù)標(biāo)志設(shè)置為0。
下面是一個(gè)簡(jiǎn)單的例子:
char *msg = "Beej was here!";
int len, bytes_sent;
len = strlen(msg);
bytes_sent = send(sockfd, msg, len, 0);
系統(tǒng)調(diào)用s e n d ( )返回實(shí)際發(fā)送的字節(jié)數(shù),這可能比你實(shí)際想要發(fā)送的字節(jié)數(shù)少。如果返回
的字節(jié)數(shù)比要發(fā)送的字節(jié)數(shù)少,你在以后必須發(fā)送剩下的數(shù)據(jù)。當(dāng)s e n d ( )出錯(cuò)時(shí),將返回- 1。
系統(tǒng)調(diào)用r e c v ( )的使用方法和s e n d ( )類(lèi)似:
int recv(int sockfd, void *buf, int len, unsigned int flags);
第一個(gè)參數(shù)是要讀取的套接口文件描述符。第二個(gè)參數(shù)是保存讀入信息的地址。第三個(gè)參
數(shù)是緩沖區(qū)的最大長(zhǎng)度。第四個(gè)參數(shù)設(shè)置為0。
系統(tǒng)調(diào)用r e c v ( )返回實(shí)際讀取到緩沖區(qū)的字節(jié)數(shù),如果出錯(cuò)則返回- 1。
這樣使用上面的系統(tǒng)調(diào)用,你可以通過(guò)數(shù)據(jù)流套接口來(lái)發(fā)送和接受信息。
5.7 sendto() 和recvfrom()
因?yàn)閿?shù)據(jù)報(bào)套接口并不連接到遠(yuǎn)程的主機(jī)上,所以在發(fā)送數(shù)據(jù)包之前,我們必須首先給出
目的地址,請(qǐng)看:
int sendto(int sockfd, const void *msg, int len, unsigned int flags,
const struct sockaddr *to, int tolen);
除了兩個(gè)參數(shù)以外,其他的參數(shù)和系統(tǒng)調(diào)用s e n d ( )時(shí)相同。參數(shù)t o是指向包含目的I P地址
和端口號(hào)的數(shù)據(jù)結(jié)構(gòu)s o c k a d d r的指針。參數(shù)t o l e n可以設(shè)置為sizeof(struct sockaddr)。
系統(tǒng)調(diào)用s e n d t o ( )返回實(shí)際發(fā)送的字節(jié)數(shù),如果出錯(cuò)則返回- 1。
系統(tǒng)調(diào)用r e c v f r o m ( )的使用方法也和r e c v ( )的十分近似:
int recvfrom(int sockfd, void *buf, int len, unsigned int flags
struct sockaddr *from, int *fromlen);
參數(shù)f r o m是指向本地計(jì)算機(jī)中包含源I P地址和端口號(hào)的數(shù)據(jù)結(jié)構(gòu)s o c k a d d r的指針。參數(shù)
f r o m l e n設(shè)置為sizeof(struct sockaddr)。
系統(tǒng)調(diào)用r e c v f r o m ( )返回接收到的字節(jié)數(shù),如果出錯(cuò)則返回- 1。
5.8 close() 和shutdown()
你可以使用c l o s e ( )調(diào)用關(guān)閉連接的套接口文件描述符:
c l o s e ( s o c k f d ) ;
這樣就不能再對(duì)此套接口做任何的讀寫(xiě)操作了。
使用系統(tǒng)調(diào)用s h u t d o w n ( ),可有更多的控制權(quán)。它允許你在某一個(gè)方向切斷通信,或者切
斷雙方的通信:
int shutdown(int sockfd, int how);
第一個(gè)參數(shù)是你希望切斷通信的套接口文件描述符。第二個(gè)參數(shù)h o w值如下:
0—Further receives are disallowed
1—Further sends are disallowed
2—Further sends and receives are disallowed (like close())
shutdown() 如果成功則返回0,如果失敗則返回- 1。
5.9 getpeername()
這個(gè)系統(tǒng)的調(diào)用十分簡(jiǎn)單。它將告訴你是誰(shuí)在連接的另一端:
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);
第一個(gè)參數(shù)是連接的數(shù)據(jù)流套接口文件描述符。第二個(gè)參數(shù)是指向包含另一端的信息的數(shù)
據(jù)結(jié)構(gòu)s o c k a d d r的指針。第三個(gè)參數(shù)可以設(shè)置為sizeof(struct sockaddr)。
如果出錯(cuò),系統(tǒng)調(diào)用將返回- 1。
一旦你獲得了它們的地址,你可以使用inet_ntoa() 或者g e t h o s t b y a d d r ( )來(lái)得到更多的信息。
5.10 gethostname()
系統(tǒng)調(diào)用g e t h o s t n a m e ( )比系統(tǒng)調(diào)用g e t p e e r n a m e ( )還簡(jiǎn)單。它返回程序正在運(yùn)行的計(jì)算機(jī)的
名字。系統(tǒng)調(diào)用g e t h o s t b y n a m e ( )可以使用這個(gè)名字來(lái)決定你的機(jī)器的I P地址。
下面是一個(gè)例子:
#include <unistd.h>
int gethostname(char *hostname, size_t size);
如果成功,g e t h o s t n a m e將返回0。如果失敗,它將返回- 1。
6 DNS
DNS 代表“Domain Name Service”,即域名服務(wù)器。它可以把域名翻譯成相應(yīng)的I P地址。
你可以使用此I P地址調(diào)用b i n d ( )、c o n n e c t ( )、s e n d t o ( )或者用于其他的地方。
系統(tǒng)調(diào)用g e t h o s t b y n a m e ( )可以完成這個(gè)函數(shù):
#include <netdb.h>
struct hostent *gethostbyname(const char *name);
它返回一個(gè)指向數(shù)據(jù)結(jié)構(gòu)h o s t e n t的指針,數(shù)據(jù)結(jié)構(gòu)h o s t e n t如下:
struct hostent {
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
} ;
#define h_addr h_addr_list[0]
h_name —主機(jī)的正式名稱(chēng)。
h_aliases —主機(jī)的別名。
h _ a d d r t y p e—將要返回的地址的類(lèi)型,一般是A F _ I N E T。
h _ l e n g t h—地址的字節(jié)長(zhǎng)度。
h _ a d d r _ l i s t—主機(jī)的網(wǎng)絡(luò)地址。
h_addr —h _ a d d r _ l i s t中的第一個(gè)地址。
系統(tǒng)調(diào)用g e t h o s t b y n a m e ( )返回一個(gè)指向填充好的數(shù)據(jù)結(jié)構(gòu)h o s t e n t的指針。當(dāng)發(fā)生錯(cuò)誤時(shí),
則返回一個(gè)N U L L指針。下面是一個(gè)實(shí)際例子:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
struct hostent *h;
if (argc != 2) { /* error check the command line */
f p r i n t f ( s t d e r r,"usage: getip address\n");
e x i t ( 1 ) ;
}
if ((h=gethostbyname(argv[1])) == NULL) { /* get the host info */
h e r r o r ( " g e t h o s t b y n a m e " ) ;
e x i t ( 1 ) ;
}
printf("Host name : %s\n", h->h_name);
printf("IP Address : %s\n",inet_ntoa(*((struct in_addr *)h->h_addr)));
return 0;
}
在使用g e t h o s t b y n a m e ( )時(shí),你不能使用p e r r o r ( )來(lái)打印錯(cuò)誤信息。你應(yīng)該使用的是系統(tǒng)調(diào)用
h e r r o r ( )。
7 客戶(hù)機(jī)/服務(wù)器模式
在網(wǎng)絡(luò)上大部分的通信都是在客戶(hù)機(jī)/服務(wù)器模式下進(jìn)行的。例如t e l n e t。當(dāng)你使用t e l n e t連
接到遠(yuǎn)程主機(jī)的端口2 3時(shí),主機(jī)上的一個(gè)叫做t e l n e t d的程序就開(kāi)始運(yùn)行。它處理所有進(jìn)入的
t e l n e t連接,為你設(shè)置登錄提示符等。
應(yīng)當(dāng)注意的是客戶(hù)機(jī)/服務(wù)器模式可以使用S O C K _ S T R E A M、S O C K _ D G R A M或者任何其
他的方式。例如t e l n e t / t e l n e t d、f t p / f t p d和b o o t p / b o o t p d。每當(dāng)你使用f t p時(shí),遠(yuǎn)程計(jì)算機(jī)都在運(yùn)
行一個(gè)f t p d為你服務(wù)。
一般情況下,一臺(tái)機(jī)器上只有一個(gè)服務(wù)器程序,它通過(guò)使用f o r k ( )來(lái)處理多個(gè)客戶(hù)端程序
的請(qǐng)求。最基本的處理方法是:服務(wù)器等待連接,使用a c c e p t ( )接受連接,調(diào)用f o r k ( )生成一個(gè)
子進(jìn)程處理連接。
8 簡(jiǎn)單的數(shù)據(jù)流服務(wù)器程序
此服務(wù)器程序所作的事情就是通過(guò)一個(gè)數(shù)據(jù)流連接發(fā)送字符串“ Hello, Wo r l d ! \ n”。你可以
在一個(gè)窗口上運(yùn)行此程序,然后在另一個(gè)窗口使用t e l n e t:
$ telnet remotehostname 3490
其中,r e m o t e h o s t n a m e是你運(yùn)行的機(jī)器名。下面是此程序的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#define MYPORT 3490 /* the port users will be connecting to */
#define BACKLOG 10 /* how many pending connections queue will hold */
m a i n ( )
{
int sockfd, new_fd; /* listen on sock_fd, new connection on new_fd */
struct sockaddr_in my_addr; /* my address information */
struct sockaddr_in their_addr; /* connector's address information */
int sin_size;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
p e r r o r ( " s o c k e t " ) ;
e x i t ( 1 ) ;
}
m y _ a d d r.sin_family = AF_INET; /* host byte order */
m y _ a d d r.sin_port = htons(MYPORT); /* short, network byte order */
m y _ a d d r. s i n _ a d d r.s_addr = INADDR_ANY; /* auto-fill with my IP */
b z e r o ( & ( m y _ a d d r.sin_zero), 8); /* zero the rest of the struct */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
p e r r o r ( " b i n d " ) ;
e x i t ( 1 ) ;
}
if (listen(sockfd, BACKLOG) == -1) {
p e r r o r ( " l i s t e n " ) ;
e x i t ( 1 ) ;
}
while(1) { /* main accept() loop */
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
p e r r o r ( " a c c e p t " ) ;
c o n t i n u e ;
}
printf("server: got connection from %s\n", \
i n e t _ n t o a ( t h e i r _ a d d r. s i n _ a d d r ) ) ;
if (!fork()) { /* this is the child process */
if (send(new_fd, "Hello, world!\n", 14, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); /* parent doesn't need this */
while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
}
}
你也可以使用下面的客戶(hù)機(jī)程序從服務(wù)器上得到字符串。
9 簡(jiǎn)單的數(shù)據(jù)流客戶(hù)機(jī)程序
客戶(hù)機(jī)所做的是連接到你在命令行中指定的主機(jī)的3 4 9 0端口。它讀取服務(wù)器發(fā)送的字符
串。
下面是客戶(hù)機(jī)程序的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 3490 /* the port client will be connecting to */
#define MAXDATASIZE 100 /* max number of bytes we can get at once */
int main(int argc, char *argv[])
{
int sockfd, numbytes;
char buf[MAXDATA S I Z E ] ;
struct hostent *he;
struct sockaddr_in their_addr; /* connector's address information */
if (argc != 2) {
f p r i n t f ( s t d e r r,"usage: client hostname\n");
e x i t ( 1 ) ;
}
if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
h e r r o r ( " g e t h o s t b y n a m e " ) ;
e x i t ( 1 ) ;
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
p e r r o r ( " s o c k e t " ) ;
e x i t ( 1 ) ;
}
t h e i r _ a d d r.sin_family = AF_INET; /* host byte order */
t h e i r _ a d d r.sin_port = htons(PORT); /* short, network byte order */
t h e i r _ a d d r.sin_addr = *((struct in_addr *)he->h_addr);
b z e r o ( & ( t h e i r _ a d d r.sin_zero), 8); /* zero the rest of the struct */
if (connect(sockfd, (struct sockaddr *)&their_addr, \
sizeof(struct sockaddr)) == -1) {
p e r r o r ( " c o n n e c t " ) ;
e x i t ( 1 ) ;
}
if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1) {
p e r r o r ( " r e c v " ) ;
e x i t ( 1 ) ;
}
buf[numbytes] = '\0';
printf("Received: %s",buf);
c l o s e ( s o c k f d ) ;
return 0;
}
如果你在運(yùn)行服務(wù)器程序之前運(yùn)行客戶(hù)機(jī)程序,則將會(huì)得到一個(gè)“ Connection refused”的
信息。
10 數(shù)據(jù)報(bào)套接口
程序l i s t e n e r在機(jī)器中等待端口4 9 5 0到來(lái)的數(shù)據(jù)包。程序t a l k e r向指定的機(jī)器的4 9 5 0端口發(fā)
送數(shù)據(jù)包。
下面是l i s t e n e r. c的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#define MYPORT 4950 /* the port users will be sending to */
#define MAXBUFLEN 100
m a i n ( )
{
int sockfd;
struct sockaddr_in my_addr; /* my address information */
struct sockaddr_in their_addr; /* connector's address information */
int addr_len, numbytes;
char buf[MAXBUFLEN];
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
my_addr.sin_family = AF_INET; /* host byte order */
my_addr.sin_port = htons(MYPORT); /* short, network byte order */
my_a d d r.s i n_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind ") ;
exit(1);
}
addr_len = sizeof(struct sockaddr);
if ((numbytes=recvfrom(sockfd, buf, MAXBUFLEN, 0, \
(struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror( "recvfrom" );
exit(1) ;
}
printf("got packet from %s\n",inet_ntoa(their_addr. s i n _ a d d r ) ) ;
printf("packet is %d bytes long\n",numbytes);
buf[numbytes] = '\0';
printf("packet contains \"%s\"\n",buf);
close(sockfd);
}
下面是t a l k e r. c的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>
#define MYPORT 4950 /* the port users will be sending to */
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in their_addr; /* connector's address information */
struct hostent *he;
int numbytes;
if (argc != 3) {
fprintf (stderr, "usage: talker hostname message\n");
exit(1);
}
if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
h e r r o r ( " g e t h o s t b y n a m e " ) ;
e x i t ( 1 ) ;
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket") ;
exit(1);
}
their_addr.sin_family = AF_INET; /* host byte order */
their_addr.sin_port = htons(MYPORT); /* short, network byte order */
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */
if ((numbytes=sendto(sockfd, argv[2], strlen(argv[2]), 0, \
(struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1) {
perror ("s e n d t o");
exit(1);
}
printf("sent %d bytes to %s\n",numbytes,inet_ntoa(their_addr. s i n _ a d d r ) ) ;
close(sockfd);
return 0;
}
你可以在一臺(tái)機(jī)器上運(yùn)行l(wèi) i s t e n e r程序,在另一臺(tái)機(jī)器上運(yùn)行t a l k e r程序,然后觀察它們之
間的通信。
21.11 阻塞
當(dāng)使用上面的listener程序時(shí),此程序在等待直到一個(gè)數(shù)據(jù)包到來(lái)。這是因?yàn)樗{(diào)用了
recvform(),如果沒(méi)有數(shù)據(jù),recvform ( )就一直阻塞,直到有數(shù)據(jù)到來(lái)。
很多函數(shù)都有阻塞。系統(tǒng)調(diào)用accept ( )阻塞,所有的類(lèi)似recv*()的函數(shù)也可以阻塞。它們
之所以可以阻塞是因?yàn)橄到y(tǒng)內(nèi)核允許它們阻塞。當(dāng)你第一次創(chuàng)建一個(gè)套接口文件描述符時(shí),系
統(tǒng)內(nèi)核將它設(shè)置為可以阻塞。如果你不希望套接口阻塞,你可以使用系統(tǒng)調(diào)用fcntl():
#include <unistd.h>
#include <fcntl.h>
.
sockfd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
.
如果你設(shè)置為不阻塞,那么就得頻繁地詢(xún)問(wèn)套接口以便檢查有無(wú)信息到來(lái)。如果你試圖讀
取一個(gè)沒(méi)有阻塞的套接口,同時(shí)它又沒(méi)有數(shù)據(jù),那么你將得到- 1。
詢(xún)問(wèn)套接口以檢查有無(wú)信息得到來(lái)可能會(huì)占用太多的C P U時(shí)間。另一個(gè)可以使用的方法是
select()。
select()用于同步I / O多路復(fù)用。這個(gè)系統(tǒng)調(diào)用十分有用。考慮一下下面的情況:你是一個(gè)
服務(wù)器,你希望監(jiān)聽(tīng)進(jìn)入的連接,同時(shí)還一直從已有的連接中讀取信息。
也許你認(rèn)為可以使用一個(gè)accept()調(diào)用和幾個(gè)recv()調(diào)用。但如果調(diào)用accept()阻塞了怎么
辦?如果在這時(shí)你希望調(diào)用recv()接受數(shù)據(jù)呢?
系統(tǒng)調(diào)用select()使得你可以同時(shí)監(jiān)視幾個(gè)套接口。它可以告訴你哪一個(gè)套接口已經(jīng)準(zhǔn)備好
了以供讀取,哪一個(gè)套接口已經(jīng)可以寫(xiě)入。
下面是select()的用法:
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int numfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
此函數(shù)監(jiān)視幾個(gè)文件描述符,特別是r e a d f d s、w r i t e f d s和e x c e p t f d s。如果你希望檢查是否
可以從標(biāo)準(zhǔn)輸入中和一些其他的套接口文件描述符s o c k f d中讀取數(shù)據(jù),只需把文件描述符0和
s o c k f d添加到r e a d f d s中。參數(shù)n u m f d s應(yīng)該設(shè)置為最高的文件描述符的值加1。
當(dāng)s e l e c t ( )返回時(shí),r e a d f d s將會(huì)被修改以便反映你選擇的那一個(gè)文件描述符已經(jīng)準(zhǔn)備好了以
供讀取。你可以使用F D _ I S S E T ( )測(cè)試。
FD_ZERO(fd_set *set)—清除文件描述符集。
FD_SET(int fd, fd_set *set)—把fd 添加到文件描述符集中。
FD_CLR(int fd, fd_set *set)—把fd 從文件描述符中移走。
FD_ISSET(int fd, fd_set *set)—檢測(cè)fd 是否在文件描述符集中。
數(shù)據(jù)結(jié)構(gòu)t i m e v a l包含下面的字段:
struct timeval {
int tv_sec; /* seconds */
int tv_usec; /* microseconds */
} ;
把t v _ s e c設(shè)置成需要等待的時(shí)間秒數(shù),t v _ u s e c設(shè)置成需要等待的微秒數(shù)。一秒中包括1 000
0 0 0 μ s 。下面的程序等待2 . 5 s:
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0 /* file descriptor for standard input */
m a i n ( )
{
struct timeval tv;
fd_set readfds;
t v.tv_sec = 2;
t v.tv_usec = 500000;
F D _ Z E R O ( & r e a d f d s ) ;
FD_SET(STDIN, &readfds);
/* don't care about writefds and exceptfds: */
select(STDIN+1, &readfds, NULL, NULL, &tv);
if (FD_ISSET(STDIN, &readfds))
printf("A key was pressed!\n");
else
printf( " Timed out.\n");
摘自:
Linux系統(tǒng)高級(jí)編程-china pub
posted on 2009-11-15 21:40 chatler 閱讀(745) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): Socket
<2010年5月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

常用鏈接

留言簿(10)

隨筆分類(lèi)(307)

隨筆檔案(297)

algorithm

Books_Free_Online

C++

database

Linux

Linux shell

linux socket

misce

  • cloudward
  • 感覺(jué)這個(gè)博客還是不錯(cuò),雖然做的東西和我不大相關(guān),覺(jué)得看看還是有好處的

network

OSS

  • Google Android
  • Android is a software stack for mobile devices that includes an operating system, middleware and key applications. This early look at the Android SDK provides the tools and APIs necessary to begin developing applications on the Android platform using the Java programming language.
  • os161 file list

overall

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            99xxxx成人网| 红桃视频成人| 国产一区二区三区在线观看精品| 亚洲国产成人在线播放| 性欧美暴力猛交69hd| 亚洲国产婷婷香蕉久久久久久| 亚洲欧美成人网| 欧美视频在线观看免费| 99香蕉国产精品偷在线观看| 欧美激情一区二区三区在线| 久久久噜噜噜久噜久久| 韩国成人精品a∨在线观看| 欧美一区二区三区四区在线观看| 亚洲一区999| 欧美午夜理伦三级在线观看| 9色porny自拍视频一区二区| 亚洲精一区二区三区| 欧美日本成人| 亚洲一区999| 亚洲资源在线观看| 国产视频不卡| 久久乐国产精品| 美女图片一区二区| 亚洲精品国久久99热| 亚洲国产日韩美| 欧美噜噜久久久xxx| 一个色综合av| 国产精品99久久99久久久二8| 国产精品久久久久久久久果冻传媒 | 日韩视频二区| 99re6这里只有精品| 欧美亚洲成人精品| 欧美一区二区三区另类| 久久国产免费| 亚洲日韩欧美视频| 日韩视频精品| 国产亚洲激情在线| 亚洲电影免费在线 | 欧美日韩国产一区| aa级大片欧美| 国产欧美日韩麻豆91| 麻豆精品精品国产自在97香蕉| 乱码第一页成人| 正在播放欧美视频| 午夜电影亚洲| 亚洲精选视频免费看| 中文精品视频一区二区在线观看| 国产视频一区二区在线观看| 欧美成人在线网站| 欧美视频亚洲视频| 麻豆成人在线播放| 国产精品国码视频| 欧美成年人网站| 国产精品久久久久7777婷婷| 久久久久成人网| 欧美精品一区二区高清在线观看| 欧美一级片一区| 欧美国内亚洲| 久久久99国产精品免费| 欧美日韩国产成人在线免费| 久久视频在线看| 国产精品xvideos88| 牛牛影视久久网| 国产精品日韩欧美一区二区三区| 欧美国产一区二区三区激情无套| 国产精品欧美精品| 亚洲欧洲日产国产网站| 激情视频一区二区三区| 亚洲一区二区av电影| 亚洲久久一区| 久久综合给合久久狠狠狠97色69| 午夜视频久久久久久| 欧美日韩国产成人在线免费| 欧美国产精品劲爆| 激情六月婷婷久久| 性欧美1819sex性高清| 亚洲深夜福利视频| 欧美高清不卡在线| 欧美激情一二区| 在线日韩欧美视频| 久久精品91久久香蕉加勒比| 小嫩嫩精品导航| 国产精品九九久久久久久久| 日韩视频免费观看高清在线视频| 91久久久久久久久久久久久| 久久久久国产精品麻豆ai换脸| 久久国产黑丝| 国产欧美日韩精品a在线观看| 亚洲午夜高清视频| 亚洲男女自偷自拍图片另类| 欧美视频中文在线看| 99ri日韩精品视频| 亚洲综合国产精品| 国产精品久久久久免费a∨大胸| 日韩写真在线| 亚洲一区在线看| 国产精品蜜臀在线观看| 亚洲欧美激情四射在线日| 欧美一级久久久久久久大片| 国产色视频一区| 久久精品青青大伊人av| 久久综合免费视频影院| 亚洲第一综合天堂另类专| 蜜臀久久久99精品久久久久久 | 欧美在线三级| 久久综合中文字幕| 欧美理论电影在线观看| 国产精品久久久99| 亚洲精品字幕| 老司机精品导航| 午夜日韩在线观看| 国产精品久久久久毛片大屁完整版| 在线播放亚洲| 美女精品一区| 毛片一区二区| 在线观看欧美日韩国产| 久久久久久夜| 9i看片成人免费高清| 久久国产一区| 亚洲国产精品一区在线观看不卡 | 亚洲摸下面视频| 一本色道久久综合亚洲精品按摩| 蜜桃久久精品乱码一区二区| 极品尤物av久久免费看| 久久蜜臀精品av| 久久综合色综合88| 最新国产成人在线观看| 亚洲精品一区二区三区婷婷月 | 欧美一级视频| 欧美一区二区三区婷婷月色| 国产日本欧美一区二区| 美女999久久久精品视频| 久久综合久色欧美综合狠狠| 一区二区欧美亚洲| 亚洲欧美卡通另类91av| 一区二区在线视频观看| 亚洲日韩中文字幕在线播放| 欧美韩国日本综合| 午夜精品999| 老司机精品久久| 欧美一区二区精品在线| 国产精品99久久久久久久久久久久| 国产精品萝li| 亚洲国产精品欧美一二99| 国产欧美日韩一区二区三区在线| 欧美大色视频| 国产一区二区三区在线观看免费视频| 欧美激情精品久久久| 国外成人在线| 亚洲一区二区av电影| 在线国产日韩| 一区二区三区毛片| 日韩亚洲在线观看| 亚洲精品在线二区| 久久伊伊香蕉| 久久亚裔精品欧美| 国产专区欧美精品| 亚洲女爱视频在线| 性欧美1819sex性高清| 欧美日韩精品系列| 欧美不卡福利| 亚洲精品国产精品国产自| 久久天天躁夜夜躁狠狠躁2022 | 99精品视频一区二区三区| 欧美在线免费观看| 久久久综合香蕉尹人综合网| 狠狠色丁香婷综合久久| 久久视频国产精品免费视频在线 | 欧美成人午夜激情视频| 亚洲国产精品久久久久| 欧美顶级少妇做爰| 在线视频日本亚洲性| 久久久99国产精品免费| 亚洲成人在线免费| 欧美视频免费在线观看| 欧美在线观看一区二区三区| 女生裸体视频一区二区三区| 亚洲啪啪91| 国产精品一区二区三区久久久| 性色一区二区三区| 亚洲欧洲日本国产| 久久免费高清视频| 亚洲女同精品视频| 在线精品国精品国产尤物884a| 欧美日韩一区在线| 午夜精品福利在线| 在线日韩av片| 国产精品入口日韩视频大尺度| 久久蜜桃精品| 欧美一区亚洲二区| 亚洲一区二区视频在线观看| 亚洲第一二三四五区| 久久婷婷av| 久久国产毛片| 久久av一区| 久久成人综合视频| 午夜欧美精品| 香蕉精品999视频一区二区 | 夜夜嗨av一区二区三区免费区| 狠狠干狠狠久久|