程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Linux網絡編程2——系統函數,linux網絡編程函數

Linux網絡編程2——系統函數,linux網絡編程函數

編輯:關於C語言

Linux網絡編程2——系統函數,linux網絡編程函數


socket信息數據結構

#include <netinet/in.h>

struct sockaddr 
{
    unsigned short sa_family;      /*地址族*/
    char sa_data[14];              /*14字節的協議地址,包含該socket的IP地址和端口號。*/
};
struct sockaddr_in 
{
    short int sa_family;           /*地址族*/
    unsigned short int sin_port;   /*端口號*/
    struct in_addr sin_addr;       /*IP地址*/
    unsigned char sin_zero[8];     /*填充0 以保持與struct sockaddr同樣大小*/
};
struct in_addr
{
        unsigned long int  s_addr;    /* 32位IPv4地址,網絡字節序 */
};
#include <netinet/in.h>

tips
sa_family:
AF_INET   -> IPv4協議  
AF_INET6  -> IPv6協議

注意

結構體struct in_addr中存放的s_addr,是無符號整型數。實際上32位IPv4地址為點分十進制,每個字節的范圍均為0-255,只要高字節大於等於128,那麼這個整型數必然為負數,只不過我們這邊僅僅關心ip每一位的存儲情況,因此此處可以使用無符號數進行存儲。

函數原型1

SYNOPSIS
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>
             
             
       int inet_aton(const char *cp, struct in_addr *inp);/* 注意,參數inp為傳出參數 */
       char *inet_ntoa(struct in_addr in);
實際上,我們在上篇文章中實現的三個函數是有系統函數可以直接調用的。我們的my_atoh,my_hton合並為系統函數inet_aton,而my_ntoa即為系統函數inet_ntoa。

舉例1

/*************************************************************************
    > File Name: test.c
    > Author: KrisChou
    > Mail:[email protected] 
    > Created Time: Wed 27 Aug 2014 11:06:11 PM CST
 ************************************************************************/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    char ip_buf[] = "180.97.33.107";
    struct in_addr my_addr;
    inet_aton(ip_buf,&my_addr);
    printf("ip : %s \n", ip_buf);
    printf("net: %x \n", my_addr.s_addr);
    return 0;
}

運行結果

[purple@localhost 0827]$ gcc -o test test.c -Wall
[purple@localhost 0827]$ ./test
ip : 180.97.33.107
net: 6b2161b4
照理,網絡字節序是大端存儲,應該返回0xb461216b。實際上調用系統函數inet_aton後,就直接在變量my_addr.s_addr的實際內存空間中以二進制形式寫入了0xb461216b(其實用位運算,就可以直接操作二進制位,上篇博文有具體實現)。之所以運行結果是0x6b2161b4,是因為我們的主機是小端存儲,用printf顯示結果是先取低字節。

舉例2

/*************************************************************************
    > File Name: test1.c
    > Author: KrisChou
    > Mail:[email protected] 
    > Created Time: Wed 27 Aug 2014 11:43:26 PM CST
 ************************************************************************/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    struct in_addr my_addr;
    my_addr.s_addr = 0xb461216b;
    printf("net: %x \n", my_addr.s_addr);
    printf("ip : %s \n", inet_ntoa(my_addr));
    return 0;
}
運行結果
[purple@localhost 0827]$ gcc -o test1 test1.c -Wall
[purple@localhost 0827]$ ./test1
net: b461216b
ip : 107.33.97.180
照理,ip應該輸出的是180.97.33.107。其實道理很簡單,我們的主機是小端模式存儲,而網絡字節序是大端模式,當我們把0xb461216b賦值給my_addr.s_addr 時,實際上在內存中存儲形式是0x6b2161b4,而inet_ntoa的具體實現時通過位運算直接操縱二進制位的,因此結果就自然輸出107.33.97.180。

函數原型2

SYNOPSIS
       #include <netdb.h>
       struct hostent *gethostbyname(const char *name);

The hostent structure is defined in <netdb.h> as follows:

           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 */

       The members of the hostent structure are:

       h_name The official name of the host.

       h_aliases
              An array of alternative names for the host, terminated by a NULL
              pointer.

       h_addrtype
              The type of address; always AF_INET or AF_INET6 at present.

       h_length
              The length of the address in bytes.

       h_addr_list
              An  array of pointers to network addresses for the host (in net-
              work byte order), terminated by a NULL pointer.

       h_addr The first address in h_addr_list for backward compatibility.

代碼

/*************************************************************************
  > File Name: my_host.c
  > Author: KrisChou
  > Mail:[email protected] 
  > Created Time: Wed 27 Aug 2014 05:22:46 PM CST
 ************************************************************************/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, char* argv[])// exe hostname
{
    struct hostent* p ;
    p = gethostbyname(argv[1]) ;
    /*
    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]
 */ 
    printf("host name: %s \n", p ->h_name);
    
    int index ;
    char** pp  = p -> h_aliases ;
    for(index = 0 ; pp[index] != NULL; index ++ )
    {
        printf("alias : %s \n", pp[index]);
    }
    
    printf("ip type : %d\n", p ->h_addrtype);
    
    printf("addr len : %d \n", p ->h_length);
    
    pp = p ->h_addr_list ;
    for(index = 0; pp[index] != NULL ; index ++)
    {
        /* 由於h_addr_list是一個字符串指針數組,數組中存放的指針指向一個網絡字節序 
            但是系統函數inet_ntoa需要傳入的參數是一個結構體,因此需要進行轉換。
            pp[index]是一個char*類型的指針,先將其轉換為struct in_addr*類型的指針,
            接著去引用,即得到結構體。                                                 */
        printf("ip : %s \n", inet_ntoa( *(struct in_addr *)pp[index] ) );
    }
    
    return 0 ;
}
運行結果
[purple@localhost 0827]$ gcc -o myhost my_host.c -Wall
[purple@localhost 0827]$ ./myhost www.baidu.com
host name: www.a.shifen.com
alias : www.baidu.com
ip type : 2
addr len : 4
ip : 180.97.33.107
ip : 180.97.33.108

干貨

某年騰訊面試題:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int a = 0x61;//97
    printf("%x\n",(char*)(&a)[0]);
}

結果輸出61,說明是小端機,先存低字節。

總結

切記系統函數無論inet_aton還是inet_ntoa,都是直接以位運算形式實現的,因此其關注的是數據在內存中實際的二進制存儲形式。


推薦linux c函數實現的書

意思你想看源代碼?一般都是以標准庫+頭文件的形式。。。。
看源碼的話,就去下載glibc的源碼包,裡面包含了gnu的c函數庫的源碼。

這方面的書似乎沒見過,一般都不會去分析標准庫,而是分析內核源碼。

這個鏈接是介紹glibc的
hi.baidu.com/...9.html

這個連接是下載glibc的:(自己仔細看下,是英文的)
www.gnu.org/s/libc/resources.html

書的話,很抱歉就看到這個:程序員的自我修養:鏈接、裝載與庫(似乎是說windows的)
不過我搜索的時候看到這裡面的11章說到了一些,具體我沒有看~~~

剩下的就看你自己咯~~
 

linux網絡編程的I/O多路復用是為何?該怎使用?

linux網絡編程的I/O 多路復用。select()函數是系統提供的,它可以在多個描
述符中選擇被激活的描述符進行操作。
例如:一個進程中有多個客戶連接,即存在多個TCP 套接字描述符。select()函數阻塞
直到任何一個描述符被激活,即有數據傳輸。從而避免了進程為等待一個已連接上的數據而
無法處理其他連接。因而,這是一個時分復用的方法,從用戶角度而言,它實現了一個進程
或線程中的並發處理。
I/O 多路復用技術的最大優勢是系統開銷小,系統不必創建進程、線程,也不必維護這
些進程/線程,從而大大減少了系統的開銷。
select()函數用於實現I/O 多路復用,它允許進程指示系統內核等待多個事件中的任何一
個發生,並僅在一個或多個事情發送或經過某指定的時間後才喚醒進程。
它的原型如下,
#include<sys/time.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set * errorfds, struct timeval *timeout);
ndfs: select() 函數監視描述符數的最大值。根據進程中打開的描述符數而定,一般設為要
監視的描述符的最大數加1。
readfds: select() 函數監視的可讀描述符集合。
writefds: select()函數監視的可寫描述符集合。
errorfds: select()函數監視的異常描述符集合。
timeout: select()函數超時結束時間
返回值。如果成功返回總的位數,這些位對應已准備好的描述符。否則返回-1,並在errno
中設置相應的錯誤碼。
FD_ZERO(fd_set *fdset):清空fdset 與所有描述符的聯系
FD_SET(int fd, fd_set *fdset):建立描述符fd 與fdset 的聯系
FD_CLR(int fd, fd_set *fdset):撤銷描述符fd 與fdset 的聯系
FD_ISSET(int fd,fd_set *fdset) ::檢查與fdset 聯系的描述符fd 是否可讀寫,返回非0表示可讀寫。
采用select()函數實現I/O 多路復用的基本步驟如下:
(1) 清空描述符集合
(2) 建立需要監視的描述符與描述符集合的聯系
(3) 調用select()函數
(4) 檢查所有需要監視的描述符,利用FD_ISSET 判斷是否准備好
(5) 對已准備好的描述符進行I/O 操作
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved