• <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>
            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)進程通信的一種方法。
            因為在UNIX系統(tǒng)中,所有的I/O操作都是通過讀寫文件描述符而產(chǎn)生的。文件描述符就是
            一個和打開的文件相關(guān)連的整數(shù)。但文件可以是一個網(wǎng)絡(luò)連接、一個FIFO、一個管道、一個
            終端、一個真正存儲在磁盤上的文件或者UNIX系統(tǒng)中的任何其他的東西。所以,如果你希望
            通過Internet和其他的程序進行通信,你只有通過文件描述符。
            使用系統(tǒng)調(diào)用socket(),你可以得到socket()描述符。然后你可以使用send() 和recv()調(diào)用而
            與其他的程序通信。你也可以使用一般的文件操作來調(diào)用read() 和write()而與其他的程序進行
            通信,但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”的順序到達。它們也可以被認為是無錯誤的傳輸。
            經(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)
            答的方式進行數(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等)。
            • 主機到主機傳輸層( 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()
            一旦你有了一個套接口以后,下一步就是把套接口綁定到本地計算機的某一個端口上。但
            如果你只想使用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)用,那么你不必知道你使用的端口號。當你調(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()
            如果你希望不連接到遠程的主機,也就是說你希望等待一個進入的連接請求,然后再處理
            它們。這樣,你通過首先調(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ù)是進入隊列中允許
            的連接的個數(shù)。進入的連接請求在使用系統(tǒng)調(diào)用a c c e p t ( )應(yīng)答之前要在進入隊列中等待。這個
            值是隊列中最多可以擁有的請求的個數(shù)。大多數(shù)系統(tǒng)的缺省設(shè)置為2 0。你可以設(shè)置為5或者1 0。
            當出錯時,l i s t e n ( )將會返回- 1值。
            當然,在使用系統(tǒng)調(diào)用l i s t e n ( )之前,我們需要調(diào)用b i n d ( )綁定到需要的端口,否則系統(tǒng)內(nèi)
            核將會讓我們監(jiān)聽一個隨機的端口。所以,如果你希望監(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ù)雜。在遠程的主機可能試圖使用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 ( )中的信息將存儲在這里。通過它你可以了解哪個主機在哪個
            端口呼叫你。第三個參數(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ù)標志設(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ù)。當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ù)報套接口并不連接到遠程的主機上,所以在發(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是指向本地計算機中包含源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 ( )還簡單。它返回程序正在運行的計算機的
            名字。系統(tǒng)調(diào)用g e t h o s t b y n a m e ( )可以使用這個名字來決定你的機器的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 —主機的正式名稱。
            h_aliases —主機的別名。
            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—主機的網(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的指針。當發(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 客戶機/服務(wù)器模式
            在網(wǎng)絡(luò)上大部分的通信都是在客戶機/服務(wù)器模式下進行的。例如t e l n e t。當你使用t e l n e t連
            接到遠程主機的端口2 3時,主機上的一個叫做t e l n e t d的程序就開始運行。它處理所有進入的
            t e l n e t連接,為你設(shè)置登錄提示符等。
            應(yīng)當注意的是客戶機/服務(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。每當你使用f t p時,遠程計算機都在運
            行一個f t p d為你服務(wù)。
            一般情況下,一臺機器上只有一個服務(wù)器程序,它通過使用f o r k ( )來處理多個客戶端程序
            的請求。最基本的處理方法是:服務(wù)器等待連接,使用a c c e p t ( )接受連接,調(diào)用f o r k ( )生成一個
            子進程處理連接。
            8 簡單的數(shù)據(jù)流服務(wù)器程序
            此服務(wù)器程序所作的事情就是通過一個數(shù)據(jù)流連接發(fā)送字符串“ Hello, Wo r l d ! \ n”。你可以
            在一個窗口上運行此程序,然后在另一個窗口使用t e l n e t:
            $ telnet remotehostname 3490
            其中,r e m o t e h o s t n a m e是你運行的機器名。下面是此程序的代碼:
            #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 */
            }
            }
            你也可以使用下面的客戶機程序從服務(wù)器上得到字符串。
            9 簡單的數(shù)據(jù)流客戶機程序
            客戶機所做的是連接到你在命令行中指定的主機的3 4 9 0端口。它讀取服務(wù)器發(fā)送的字符
            串。
            下面是客戶機程序的代碼:
            #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;
            }
            如果你在運行服務(wù)器程序之前運行客戶機程序,則將會得到一個“ Connection refused”的
            信息。
            10 數(shù)據(jù)報套接口
            程序l i s t e n e r在機器中等待端口4 9 5 0到來的數(shù)據(jù)包。程序t a l k e r向指定的機器的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;
            }
            你可以在一臺機器上運行l(wèi) i s t e n e r程序,在另一臺機器上運行t a l k e r程序,然后觀察它們之
            間的通信。
            21.11 阻塞
            當使用上面的listener程序時,此程序在等待直到一個數(shù)據(jù)包到來。這是因為它調(diào)用了
            recvform(),如果沒有數(shù)據(jù),recvform ( )就一直阻塞,直到有數(shù)據(jù)到來。
            很多函數(shù)都有阻塞。系統(tǒng)調(diào)用accept ( )阻塞,所有的類似recv*()的函數(shù)也可以阻塞。它們
            之所以可以阻塞是因為系統(tǒng)內(nèi)核允許它們阻塞。當你第一次創(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)聽進入的連接,同時還一直從已有的連接中讀取信息。
            也許你認為可以使用一個accept()調(diào)用和幾個recv()調(diào)用。但如果調(diào)用accept()阻塞了怎么
            辦?如果在這時你希望調(diào)用recv()接受數(shù)據(jù)呢?
            系統(tǒng)調(diào)用select()使得你可以同時監(jiān)視幾個套接口。它可以告訴你哪一個套接口已經(jīng)準備好
            了以供讀取,哪一個套接口已經(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。如果你希望檢查是否
            可以從標準輸入中和一些其他的套接口文件描述符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。
            當s e l e c t ( )返回時,r e a d f d s將會被修改以便反映你選擇的那一個文件描述符已經(jīng)準備好了以
            供讀取。你可以使用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 閱讀(739) 評論(0)  編輯 收藏 引用 所屬分類: Socket
            <2010年8月>
            25262728293031
            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

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            成人国内精品久久久久影院| 久久99久久无码毛片一区二区| 久久99国产精品久久| 久久AV高潮AV无码AV| 国产ww久久久久久久久久| 久久综合亚洲欧美成人| 国产香蕉久久精品综合网| 久久青青草原亚洲av无码| 久久综合视频网站| 久久综合偷偷噜噜噜色| 久久婷婷五月综合成人D啪| 亚洲国产成人精品女人久久久 | 91麻精品国产91久久久久| 青青青国产成人久久111网站| 99久久免费国产特黄| 国产精品欧美久久久久无广告| 一本一道久久精品综合| 亚洲精品高清久久| 久久无码精品一区二区三区| 欧美亚洲国产精品久久高清| 久久亚洲美女精品国产精品| 香蕉99久久国产综合精品宅男自| 久久99国产综合精品女同| 一本久久综合亚洲鲁鲁五月天亚洲欧美一区二区 | 91久久精品视频| 69久久精品无码一区二区| 午夜欧美精品久久久久久久| 国产69精品久久久久久人妻精品| 99久久国产精品免费一区二区 | 久久国产精品久久国产精品| 久久er国产精品免费观看2| 国产—久久香蕉国产线看观看 | 久久精品极品盛宴观看| 久久精品国产男包| 色狠狠久久AV五月综合| 欧美亚洲国产精品久久蜜芽| 热久久最新网站获取| 欧美国产成人久久精品| 国产精品成人久久久久三级午夜电影 | 国内精品久久久久久久97牛牛| 国产三级精品久久|