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

posts - 297,  comments - 15,  trackbacks - 0
本文介紹Linux系統(tǒng)網(wǎng)絡(luò)編程的內(nèi)容,如套接口的概念與使用、網(wǎng)絡(luò)編程的結(jié)構(gòu)等。
1 什么是套接口
簡單地說,套接口就是一種使用UNIX系統(tǒng)中的文件描述符和系統(tǒng)進(jìn)程通信的一種方法。
因為在UNIX系統(tǒng)中,所有的I/O操作都是通過讀寫文件描述符而產(chǎn)生的。文件描述符就是
一個和打開的文件相關(guān)連的整數(shù)。但文件可以是一個網(wǎng)絡(luò)連接、一個FIFO、一個管道、一個
終端、一個真正存儲在磁盤上的文件或者UNIX系統(tǒng)中的任何其他的東西。所以,如果你希望
通過Internet和其他的程序進(jìn)行通信,你只有通過文件描述符。
使用系統(tǒng)調(diào)用socket(),你可以得到socket()描述符。然后你可以使用send() 和recv()調(diào)用而
與其他的程序通信。你也可以使用一般的文件操作來調(diào)用read() 和write()而與其他的程序進(jìn)行
通信,但send() 和recv()調(diào)用可以提供一種更好的數(shù)據(jù)通信的控制手段。下面我們討論Internet
套接口的使用方法。
2 兩種類型的Internet套接口
有兩種最常用的Internet 套接口,“數(shù)據(jù)流套接口”和“數(shù)據(jù)報套接口”,以后我們用
“SOCK_STREAM” 和“SOCK_DGRAM”分別代表上面兩種套接口。數(shù)據(jù)報套接口有時也
叫做“無連接的套接口”。
數(shù)據(jù)流套接口是可靠的雙向連接的通信數(shù)據(jù)流。如果你在套接口中以“ 1, 2”的順序放入
兩個數(shù)據(jù),它們在另一端也會以“1, 2”的順序到達(dá)。它們也可以被認(rèn)為是無錯誤的傳輸。
經(jīng)常使用的telnet應(yīng)用程序就是使用數(shù)據(jù)流套接口的一個例子。使用HTTP的WWW瀏覽器
也使用數(shù)據(jù)流套接口來讀取網(wǎng)頁。事實上,如果你使用telnet 登錄到一個WWW站點的8 0端口,
然后鍵入“GET 網(wǎng)頁名”,你將可以得到這個HTML頁。數(shù)據(jù)流套接口使用TCP得到這種高質(zhì)
量的數(shù)據(jù)傳輸。數(shù)據(jù)報套接口使用UDP,所以數(shù)據(jù)報的順序是沒有保障的。數(shù)據(jù)報是按一種應(yīng)
答的方式進(jìn)行數(shù)據(jù)傳輸?shù)摹?br>3 網(wǎng)絡(luò)協(xié)議分層
由于網(wǎng)絡(luò)中的協(xié)議是分層的,所以上層的協(xié)議是依賴于下一層所提供的服務(wù)的。也就是說,
你可以在不同的物理網(wǎng)絡(luò)中使用同樣的套接口程序,因為下層的協(xié)議對你來說是透明的。
UNIX系統(tǒng)中的網(wǎng)絡(luò)協(xié)議是這樣分層的:
• 應(yīng)用層( telnet、ftp等)。
• 主機(jī)到主機(jī)傳輸層( TCP、UDP )。
• Internet層( IP和路由)。
• 網(wǎng)絡(luò)訪問層(網(wǎng)絡(luò)、數(shù)據(jù)鏈路和物理層)。
4 數(shù)據(jù)結(jié)構(gòu)
下面我們要討論使用套接口編寫程序可能要用到的數(shù)據(jù)結(jié)構(gòu)。
首先是套接口描述符。一個套接口描述符只是一個整型的數(shù)值: i n t。
第一個數(shù)據(jù)結(jié)構(gòu)是struct sockaddr,這個數(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包括一
個目的地址和一個端口地址。
你也可以使用另一個數(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 */
} ;
這個數(shù)據(jù)結(jié)構(gòu)使得使用其中的各個元素更為方便。要注意的是sin_zero應(yīng)該使用bzero() 或
者memset()而設(shè)置為全0。另外,一個指向sockaddr_in數(shù)據(jù)結(jié)構(gòu)的指針可以投射到一個指向數(shù)
據(jù)結(jié)構(gòu)sockaddr的指針,反之亦然。
5 IP地址和如何使用IP地址
有一系列的程序可以使你處理I P地址。
首先,你可以使用inet_addr()程序把諸如“132.241.5.10”形式的IP地址轉(zhuǎn)化為無符號的整
型數(shù)。
ina.sin_addr.s_addr = inet_addr("132.241.5.10");
如果出錯,inet_addr()程序?qū)⒎祷? 1。
也可以調(diào)用inet_ntoa()把地址轉(zhuǎn)換成數(shù)字和句點的形式:
printf ("%s", inet_ntoa (ina.sin_addr));
這將會打印出I P地址。它返回的是一個指向字符串的指針。
5.1 socket()
我們使用系統(tǒng)調(diào)用socket()來獲得文件描述符:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
第一個參數(shù)domain設(shè)置為“AF_INET”。第二個參數(shù)是套接口的類型:SOCK_STREAM 或
SOCK_DGRAM。第三個參數(shù)設(shè)置為0。
系統(tǒng)調(diào)用socket()只返回一個套接口描述符,如果出錯,則返回- 1。
5.2 bind()
一旦你有了一個套接口以后,下一步就是把套接口綁定到本地計算機(jī)的某一個端口上。但
如果你只想使用connect()則無此必要。
下面是系統(tǒng)調(diào)用bind()的使用方法:
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
第一個參數(shù)sockfd 是由socket()調(diào)用返回的套接口文件描述符。第二個參數(shù)my_addr 是指向
數(shù)據(jù)結(jié)構(gòu)sockaddr的指針。數(shù)據(jù)結(jié)構(gòu)sockaddr中包括了關(guān)于你的地址、端口和I P地址的信息。
第三個參數(shù)addrlen可以設(shè)置成sizeof(struct sockaddr)。
下面是一個例子:
#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));
如果出錯,bind() 也返回- 1。
如果你使用connect()系統(tǒng)調(diào)用,那么你不必知道你使用的端口號。當(dāng)你調(diào)用connect()時,
它檢查套接口是否已經(jīng)綁定,如果沒有,它將會分配一個空閑的端口。
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);
第一個參數(shù)還是套接口文件描述符,它是由系統(tǒng)調(diào)用socket()返回的。第二個參數(shù)是
serv_addr是指向數(shù)據(jù)結(jié)構(gòu)sockaddr的指針,其中包括目的端口和I P地址。第三個參數(shù)可以使用
sizeof(struct sockaddr)而獲得。下面是一個例子:
#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));
同樣,如果出錯, c o n n e c t ( )將會返回- 1。
5.4 listen()
如果你希望不連接到遠(yuǎn)程的主機(jī),也就是說你希望等待一個進(jìn)入的連接請求,然后再處理
它們。這樣,你通過首先調(diào)用l i s t e n ( ),然后再調(diào)用a c c e p t ( )來實現(xiàn)。
系統(tǒng)調(diào)用l i s t e n ( )的形式如下:
int listen(int sockfd, int backlog);
第一個參數(shù)是系統(tǒng)調(diào)用s o c k e t ( )返回的套接口文件描述符。第二個參數(shù)是進(jìn)入隊列中允許
的連接的個數(shù)。進(jìn)入的連接請求在使用系統(tǒng)調(diào)用a c c e p t ( )應(yīng)答之前要在進(jìn)入隊列中等待。這個
值是隊列中最多可以擁有的請求的個數(shù)。大多數(shù)系統(tǒng)的缺省設(shè)置為2 0。你可以設(shè)置為5或者1 0。
當(dāng)出錯時,l i s t e n ( )將會返回- 1值。
當(dāng)然,在使用系統(tǒng)調(diào)用l i s t e n ( )之前,我們需要調(diào)用b i n d ( )綁定到需要的端口,否則系統(tǒng)內(nèi)
核將會讓我們監(jiān)聽一個隨機(jī)的端口。所以,如果你希望監(jiān)聽一個端口,下面是應(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 ( )比較起來有點復(fù)雜。在遠(yuǎn)程的主機(jī)可能試圖使用c o n n e c t ( )連接你使用
l i s t e n ( )正在監(jiān)聽的端口。但此連接將會在隊列中等待,直到使用a c c e p t ( )處理它。調(diào)用a c c e p t ( )
之后,將會返回一個全新的套接口文件描述符來處理這個單個的連接。這樣,對于同一個連接
來說,你就有了兩個文件描述符。原先的一個文件描述符正在監(jiān)聽你指定的端口,新的文件描
述符可以用來調(diào)用s e n d ( )和r e c v ( )。
調(diào)用的例子如下:
#include <sys/socket.h>
int accept(int sockfd, void *addr, int *addrlen);
第一個參數(shù)是正在監(jiān)聽端口的套接口文件描述符。第二個參數(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 ( )中的信息將存儲在這里。通過它你可以了解哪個主機(jī)在哪個
端口呼叫你。第三個參數(shù)同樣可以使用sizeof(struct sockaddr_in)來獲得。
如果出錯,a c c e p t ( )也將返回- 1。下面是一個簡單的例子:
#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來調(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);
第一個參數(shù)是你希望給發(fā)送數(shù)據(jù)的套接口文件描述符。它可以是你通過s o c k e t ( )系統(tǒng)調(diào)用
返回的,也可以是通過a c c e p t ( )系統(tǒng)調(diào)用得到的。第二個參數(shù)是指向你希望發(fā)送的數(shù)據(jù)的指針。
第三個參數(shù)是數(shù)據(jù)的字節(jié)長度。第四個參數(shù)標(biāo)志設(shè)置為0。
下面是一個簡單的例子:
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 ( )返回實際發(fā)送的字節(jié)數(shù),這可能比你實際想要發(fā)送的字節(jié)數(shù)少。如果返回
的字節(jié)數(shù)比要發(fā)送的字節(jié)數(shù)少,你在以后必須發(fā)送剩下的數(shù)據(jù)。當(dāng)s e n d ( )出錯時,將返回- 1。
系統(tǒng)調(diào)用r e c v ( )的使用方法和s e n d ( )類似:
int recv(int sockfd, void *buf, int len, unsigned int flags);
第一個參數(shù)是要讀取的套接口文件描述符。第二個參數(shù)是保存讀入信息的地址。第三個參
數(shù)是緩沖區(qū)的最大長度。第四個參數(shù)設(shè)置為0。
系統(tǒng)調(diào)用r e c v ( )返回實際讀取到緩沖區(qū)的字節(jié)數(shù),如果出錯則返回- 1。
這樣使用上面的系統(tǒng)調(diào)用,你可以通過數(shù)據(jù)流套接口來發(fā)送和接受信息。
5.7 sendto() 和recvfrom()
因為數(shù)據(jù)報套接口并不連接到遠(yuǎn)程的主機(jī)上,所以在發(fā)送數(shù)據(jù)包之前,我們必須首先給出
目的地址,請看:
int sendto(int sockfd, const void *msg, int len, unsigned int flags,
const struct sockaddr *to, int tolen);
除了兩個參數(shù)以外,其他的參數(shù)和系統(tǒng)調(diào)用s e n d ( )時相同。參數(shù)t o是指向包含目的I P地址
和端口號的數(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 ( )返回實際發(fā)送的字節(jié)數(shù),如果出錯則返回- 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ī)中包含源I P地址和端口號的數(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ù),如果出錯則返回- 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 ) ;
這樣就不能再對此套接口做任何的讀寫操作了。
使用系統(tǒng)調(diào)用s h u t d o w n ( ),可有更多的控制權(quán)。它允許你在某一個方向切斷通信,或者切
斷雙方的通信:
int shutdown(int sockfd, int how);
第一個參數(shù)是你希望切斷通信的套接口文件描述符。第二個參數(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()
這個系統(tǒng)的調(diào)用十分簡單。它將告訴你是誰在連接的另一端:
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);
第一個參數(shù)是連接的數(shù)據(jù)流套接口文件描述符。第二個參數(shù)是指向包含另一端的信息的數(shù)
據(jù)結(jié)構(gòu)s o c k a d d r的指針。第三個參數(shù)可以設(shè)置為sizeof(struct sockaddr)。
如果出錯,系統(tǒng)調(diào)用將返回- 1。
一旦你獲得了它們的地址,你可以使用inet_ntoa() 或者g e t h o s t b y a d d r ( )來得到更多的信息。
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 ( )還簡單。它返回程序正在運(yùn)行的計算機(jī)的
名字。系統(tǒng)調(diào)用g e t h o s t b y n a m e ( )可以使用這個名字來決定你的機(jī)器的I P地址。
下面是一個例子:
#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 ( )可以完成這個函數(shù):
#include <netdb.h>
struct hostent *gethostbyname(const char *name);
它返回一個指向數(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ī)的正式名稱。
h_aliases —主機(jī)的別名。
h _ a d d r t y p e—將要返回的地址的類型,一般是A F _ I N E T。
h _ l e n g t h—地址的字節(jié)長度。
h _ a d d r _ l i s t—主機(jī)的網(wǎng)絡(luò)地址。
h_addr —h _ a d d r _ l i s t中的第一個地址。
系統(tǒng)調(diào)用g e t h o s t b y n a m e ( )返回一個指向填充好的數(shù)據(jù)結(jié)構(gòu)h o s t e n t的指針。當(dāng)發(fā)生錯誤時,
則返回一個N U L L指針。下面是一個實際例子:
#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 ( )時,你不能使用p e r r o r ( )來打印錯誤信息。你應(yīng)該使用的是系統(tǒng)調(diào)用
h e r r o r ( )。
7 客戶機(jī)/服務(wù)器模式
在網(wǎng)絡(luò)上大部分的通信都是在客戶機(jī)/服務(wù)器模式下進(jìn)行的。例如t e l n e t。當(dāng)你使用t e l n e t連
接到遠(yuǎn)程主機(jī)的端口2 3時,主機(jī)上的一個叫做t e l n e t d的程序就開始運(yùn)行。它處理所有進(jìn)入的
t e l n e t連接,為你設(shè)置登錄提示符等。
應(yīng)當(dāng)注意的是客戶機(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時,遠(yuǎn)程計算機(jī)都在運(yùn)
行一個f t p d為你服務(wù)。
一般情況下,一臺機(jī)器上只有一個服務(wù)器程序,它通過使用f o r k ( )來處理多個客戶端程序
的請求。最基本的處理方法是:服務(wù)器等待連接,使用a c c e p t ( )接受連接,調(diào)用f o r k ( )生成一個
子進(jìn)程處理連接。
8 簡單的數(shù)據(jù)流服務(wù)器程序
此服務(wù)器程序所作的事情就是通過一個數(shù)據(jù)流連接發(fā)送字符串“ Hello, Wo r l d ! \ n”。你可以
在一個窗口上運(yùn)行此程序,然后在另一個窗口使用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 */
}
}
你也可以使用下面的客戶機(jī)程序從服務(wù)器上得到字符串。
9 簡單的數(shù)據(jù)流客戶機(jī)程序
客戶機(jī)所做的是連接到你在命令行中指定的主機(jī)的3 4 9 0端口。它讀取服務(wù)器發(fā)送的字符
串。
下面是客戶機(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)行客戶機(jī)程序,則將會得到一個“ Connection refused”的
信息。
10 數(shù)據(jù)報套接口
程序l i s t e n e r在機(jī)器中等待端口4 9 5 0到來的數(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;
}
你可以在一臺機(jī)器上運(yùn)行l(wèi) i s t e n e r程序,在另一臺機(jī)器上運(yùn)行t a l k e r程序,然后觀察它們之
間的通信。
21.11 阻塞
當(dāng)使用上面的listener程序時,此程序在等待直到一個數(shù)據(jù)包到來。這是因為它調(diào)用了
recvform(),如果沒有數(shù)據(jù),recvform ( )就一直阻塞,直到有數(shù)據(jù)到來。
很多函數(shù)都有阻塞。系統(tǒng)調(diào)用accept ( )阻塞,所有的類似recv*()的函數(shù)也可以阻塞。它們
之所以可以阻塞是因為系統(tǒng)內(nèi)核允許它們阻塞。當(dāng)你第一次創(chuàng)建一個套接口文件描述符時,系
統(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è)置為不阻塞,那么就得頻繁地詢問套接口以便檢查有無信息到來。如果你試圖讀
取一個沒有阻塞的套接口,同時它又沒有數(shù)據(jù),那么你將得到- 1。
詢問套接口以檢查有無信息得到來可能會占用太多的C P U時間。另一個可以使用的方法是
select()。
select()用于同步I / O多路復(fù)用。這個系統(tǒng)調(diào)用十分有用。考慮一下下面的情況:你是一個
服務(wù)器,你希望監(jiān)聽進(jìn)入的連接,同時還一直從已有的連接中讀取信息。
也許你認(rèn)為可以使用一個accept()調(diào)用和幾個recv()調(diào)用。但如果調(diào)用accept()阻塞了怎么
辦?如果在這時你希望調(diào)用recv()接受數(shù)據(jù)呢?
系統(tǒng)調(diào)用select()使得你可以同時監(jiān)視幾個套接口。它可以告訴你哪一個套接口已經(jīng)準(zhǔn)備好
了以供讀取,哪一個套接口已經(jīng)可以寫入。
下面是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)視幾個文件描述符,特別是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 ( )返回時,r e a d f d s將會被修改以便反映你選擇的那一個文件描述符已經(jīng)準(zhǔn)備好了以
供讀取。你可以使用F D _ I S S E T ( )測試。
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)—檢測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ù),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)高級編程-china pub
posted on 2009-11-15 21:40 chatler 閱讀(741) 評論(0)  編輯 收藏 引用 所屬分類: Socket
<2009年3月>
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

常用鏈接

留言簿(10)

隨筆分類(307)

隨筆檔案(297)

algorithm

Books_Free_Online

C++

database

Linux

Linux shell

linux socket

misce

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

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

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲午夜91| 国产精品免费久久久久久| 国产一区在线视频| 久久久91精品国产一区二区三区 | 久久琪琪电影院| 久久久久久欧美| 亚洲国产视频一区二区| 亚洲三级电影全部在线观看高清| 欧美高清hd18日本| 亚洲午夜国产成人av电影男同| 在线综合亚洲欧美在线视频| 国产日韩专区在线| 亚洲电影激情视频网站| 国产精品草草| 欧美成人精品一区| 欧美日韩激情网| 久久精品成人一区二区三区| 欧美成人高清视频| 欧美亚洲免费高清在线观看| 久久性天堂网| 亚洲一区二区三区四区在线观看| 欧美一级专区| 99www免费人成精品| 亚洲欧美激情视频| 日韩天天综合| 久久精品国产免费看久久精品| 99精品国产高清一区二区 | 999在线观看精品免费不卡网站| 国产精品亚洲综合一区在线观看| 蜜臀91精品一区二区三区| 欧美日韩喷水| 亚洲第一黄色网| 国产亚洲欧洲997久久综合| 亚洲精品一区二区三区福利| 一区二区三区在线不卡| 亚洲综合999| 在线亚洲观看| 欧美激情片在线观看| 久久视频一区| 国产美女搞久久| 9久草视频在线视频精品| 亚洲日本电影| 久久人人爽人人爽| 久久久久久久综合| 国产精品尤物福利片在线观看| 亚洲精品1区2区| 亚洲国产另类久久久精品极度| 亚洲欧美日韩人成在线播放| 中文在线一区| 欧美日韩免费一区二区三区| 欧美mv日韩mv亚洲| 精品va天堂亚洲国产| 亚洲综合国产精品| 国产精品无人区| 国产综合视频| 亚洲欧美日韩国产成人| 亚洲一区二区三区四区视频| 欧美巨乳波霸| 亚洲区在线播放| 99在线精品观看| 欧美国产精品人人做人人爱| 欧美韩日亚洲| 亚洲三级视频在线观看| 欧美韩日精品| 亚洲精品社区| 亚洲一区三区视频在线观看| 欧美视频二区| 亚洲一区二区视频在线观看| 香蕉免费一区二区三区在线观看| 国产精品成人免费| 亚洲一区精彩视频| 久久久国产一区二区三区| 好看的亚洲午夜视频在线| 久久久99爱| 亚洲国内在线| 亚洲少妇最新在线视频| 欧美性jizz18性欧美| 夜夜嗨av一区二区三区免费区| 亚洲一区二区三区乱码aⅴ蜜桃女| 国产精品爱啪在线线免费观看| 亚洲欧美日韩精品一区二区 | 亚洲人成网站在线观看播放| 欧美日韩福利在线观看| 亚洲欧美激情四射在线日| 久久免费午夜影院| 亚洲黄色免费| 国产精品99一区| 久久精品官网| 亚洲免费成人av| 久久久久高清| 一区二区三区精密机械公司 | 欧美人与禽猛交乱配视频| 99亚洲伊人久久精品影院红桃| 久久国产精品高清| 亚洲激情在线观看| 国产精品夜夜夜一区二区三区尤| 欧美在线一级va免费观看| 亚洲国产精品成人综合| 亚洲欧美中文日韩在线| 在线成人h网| 欧美午夜视频网站| 美腿丝袜亚洲色图| 午夜欧美精品| 亚洲精品看片| 美女爽到呻吟久久久久| 亚洲一区免费看| 亚洲国产一区在线观看| 国产欧美精品日韩区二区麻豆天美 | 亚洲在线视频观看| 亚洲高清av| 国产亚洲精品一区二555| 欧美日本中文字幕| 久久久天天操| 亚洲欧美中文字幕| 夜夜嗨一区二区三区| 欧美国产一区二区| 久久久夜夜夜| 久久精品日韩| 午夜精品久久久| 一区二区不卡在线视频 午夜欧美不卡在 | 亚洲永久免费av| 亚洲精品裸体| 亚洲电影激情视频网站| 国产酒店精品激情| 欧美视频中文字幕在线| 欧美激情精品久久久久久| 久久综合色88| 久久久久久久久久久久久久一区| 亚洲欧美日本视频在线观看| 一区二区三区四区五区在线| 亚洲精品麻豆| 亚洲国产毛片完整版| 免费在线成人| 免费亚洲婷婷| 欧美第十八页| 免费视频久久| 99精品热视频只有精品10| 六月婷婷久久| 亚洲精品一区久久久久久| 影院欧美亚洲| 影音先锋日韩精品| 伊人色综合久久天天| 激情五月综合色婷婷一区二区| 国产婷婷色一区二区三区四区| 国产精品久久久久久久久久免费| 欧美日韩亚洲高清| 欧美亚日韩国产aⅴ精品中极品| 欧美日韩综合在线| 国产精品欧美久久| 国产情侣久久| 国产欧美一区二区三区久久| 国产亚洲一区二区三区在线播放| 国产在线观看一区| 亚洲高清影视| 夜夜嗨一区二区| 亚洲你懂的在线视频| 午夜欧美精品| 久久综合久色欧美综合狠狠| 嫩模写真一区二区三区三州| 亚洲激情小视频| 亚洲神马久久| 久久av资源网| 欧美激情视频在线免费观看 欧美视频免费一 | 国产精品高清在线| 国产视频在线观看一区二区| 精品白丝av| 亚洲图片欧洲图片日韩av| 欧美在线一级va免费观看| 欧美 日韩 国产 一区| 亚洲理论在线观看| 亚洲欧美日韩国产综合| 久久天天躁狠狠躁夜夜av| 欧美精品 国产精品| 国产老女人精品毛片久久| 在线免费精品视频| 亚洲一区三区视频在线观看| 久久人人爽爽爽人久久久| 91久久久在线| 欧美一区二区三区视频| 欧美搞黄网站| 国产综合久久| 亚洲午夜羞羞片| 欧美~级网站不卡| 亚洲一卡久久| 欧美成人影音| 国产自产在线视频一区| 99精品国产在热久久| 久久久精品日韩| 蜜臀久久99精品久久久久久9| 亚洲三级色网| 亚洲免费视频网站| 欧美高清在线一区二区| 国产视频在线观看一区二区三区 | 香蕉久久精品日日躁夜夜躁| 欧美freesex8一10精品| 欧美亚洲网站| 国产精品日韩精品欧美精品| 一区二区三区视频在线播放| 欧美成人免费网| 久久se精品一区精品二区|