Linux網絡編程初步

Linux網絡編程初步

主機字節序和網絡字節序

32位置機器一次性能裝載4字節。那麼四字節在內存的順序影響它被累加器裝載成的整數的值。主要分爲大端和小端。c++

大端字節序是一個整數高位字節(23~31bit)存在內存的低處,低字節(0~7 bit) 存儲在內存的高地址處。小端相反。編程

現代PC大可能是小端序。小端就稱爲主機字節序。JVM採用大端(網絡字節序)。下面是檢測大端小段的案例數組

個人linux機子是小端序了。。。網絡

union {
        short value;
        char union_bytes[sizeof( short ) ];
    } test;
    test.value = 0x0102;
    printf("%d %d\n", test.union_bytes[0], test.union_bytes[1]);
    if(test.union_bytes[0] == 1 && test.union_bytes[1] == 2) {
        puts("大端序");
    } else if(test.union_bytes[0] == 2 && test.union_bytes[1] == 1) {
        puts("小端序");
    } else {
        puts("未知");
    }

linux下提供了四個函數來完成主機字節序和網絡字節序的轉換。dom

#include <netinet/in.h>
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);    
unsigned long int ntohl(unsigned long int netlong); 
unsigned short int ntohs(unsigned short int netshort);

例如:host to network long => htonlsocket

一個網絡編程的例子

服務端:函數

#include <bits/stdc++.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>

#define BUF_SIZE 1024


int main(int argc, char *argv[])
{
    if ( argc <= 2 )
    {
        printf("usage: %s ip_address port_number\n", basename( argv[0] ));
        return 1;
    }

    const char* ip = argv[1];
    int port = atoi( argv[2] );


    // ===================================================================================================================
    // 建立套接字
    //建立地址的結構體
    struct sockaddr_in address;                 // <netinet/in.h>
                                                //* Structure describing an Internet socket address.  */
                                                //    struct sockaddr_in
                                                //    {
                                                //       __SOCKADDR_COMMON (sin_);
                                                //        in_port_t sin_port;           /* Port number.  */
                                                //        struct in_addr sin_addr;      /* Internet address.  */
                                                //
                                                //        /* Pad to size of `struct sockaddr'.  */
                                                //        unsigned char sin_zero[sizeof (struct sockaddr) -
                                                //                __SOCKADDR_COMMON_SIZE -
                                                //                sizeof (in_port_t) -
                                                //                sizeof (struct in_addr)];
                                                //    };
    bzero(&address, sizeof( address ));         // <string.h> /* Set N bytes of S to 0.  */
                                                // extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
                                                // 裏面的sin_zero數組一般清零,因此這麼寫
    address.sin_family = AF_INET;               // AF_INET表明IPV4地址族,PF_INET是對應的協議族,宏定義的值是同樣的,理論上能夠混用

    inet_pton(AF_INET, ip, &address.sin_addr);  //  <arpa/inet.h>  
                                                //
                                                //  extern int inet_pton (int __af, const char *__restrict __cp,
                                                //  void *__restrict __buf) __THROW;
                                                //
                                                //    /* Convert from presentation format of an Internet number in buffer
                                                //      starting at CP to the binary network format and store result for
                                                //      interface type AF in buffer starting at BUF.  */

    address.sin_port = htons( port );           // 大端字節序和小段字節序的轉換 <netinet/in.h>

    int sock = socket(PF_INET, SOCK_STREAM, 0); //建立套接字    <sys/socket.h>
    assert( sock >= 0 );                        //* Create a new socket of type TYPE in domain DOMAIN, using
                                                //  protocol PROTOCOL.  If PROTOCOL is zero, one is chosen automatically.
                                                //  Returns a file descriptor for the new socket, or -1 for errors.  */
                                                //  extern int socket (int __domain, int __type, int __protocol) __THROW;
                                                //  domain: 說明系統底層的協議族,對於TCP/IP 而言,改參數設置爲PF_INET(IPV4),
                                                //          PF_INET6(IPV6), UNIX本地域協議簇,改參數設置爲 PF_UNIX
                                                //  type: 服務類型 SOCK_STREAM(流服務),SOCK_UGRAM(數據報)
                                                //        對於TCP,SOCK_STREAM 表示TCP,  SOCK_DGRAM 表示
                                                // protocol: 在前面的協議前提下的可選參數,通常給0就好
    // ===================================================================================================================

    // 命名socket
    int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ));     
    assert( ret != -1 );                        // /* Give the socket FD the local address ADDR (which is LEN bytes long).  */
                                                //  extern int bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
                                                //    __THROW;
                                                //  sock就是剛剛socket的返回值。能夠理解爲端口和IP綁定。
    
    ret = listen( sock, 5 );                    // 開始監聽。
    assert( ret != -1 );                        // /* Prepare to accept connections on socket FD.
                                                //  N connection requests will be queued before further requests are refused.
                                                //  Returns 0 on success, -1 for errors.  */
                                                //  extern int listen (int __fd, int __n) __THROW;
                                                //  第二個參數是處於徹底鏈接狀態(ESTABLISHED)的 socket上線。
    struct sockaddr_in client;
    socklen_t client_addrlength = sizeof( client ); // types.h  是個 unsigned int

    int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength);
                                                //    This function is a cancellation point and therefore not marked with
                                                //    __THROW.  */
                                                //    extern int accept (int __fd, __SOCKADDR_ARG __addr,
                                                //            socklen_t *__restrict __addr_len);
                                                //

    if(connfd < 0)
    {
        printf("errno is: %d\n", errno);
    }
    else
    {
        char buffer[ BUF_SIZE ];

        memset( buffer, '\0', BUF_SIZE );
        ret = recv( connfd, buffer, BUF_SIZE - 1, 0 );
        printf("[%d: %s]\n", ret, buffer);

        memset( buffer, '\0', BUF_SIZE );
        ret = recv( connfd, buffer, BUF_SIZE - 1, MSG_OOB );
        printf("[%d: %s]\n", ret, buffer);

        memset( buffer, '\0', BUF_SIZE );
        ret = recv( connfd, buffer, BUF_SIZE - 1, 0 );
        printf("[%d: %s]\n", ret, buffer);

        close( connfd );

    }
    close( sock );
    return 0;
}

客戶端:性能

#include <bits/stdc++.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    if(argc <= 2)
    {
        printf("usage: %s ip_address port_number\n", basename( argv[0] ));
        // basename :
        // Return the file name within directory of FILENAME.  We don't
        //  declare the function if the `basename' macro is available (defined
        //  in <libgen.h>) which makes the XPG version of this function
        //  available.
        return 1;
    }

    const char* ip = argv[1];
    int port = atoi( argv[2] );

    printf("ip = %s port = %d\n", ip, port);

    struct sockaddr_in server_address;
    bzero(&server_address, sizeof( server_address ));
    server_address.sin_family = AF_INET;    //#define PF_INET 2 //IP protocol family. // PF_INET equal AF_INET

    inet_pton( AF_INET, ip, &server_address.sin_addr );
    server_address.sin_port = htons( port );

    int sockfd = socket( PF_INET, SOCK_STREAM, 0 );
    assert( sockfd >= 0 );

    if( connect( sockfd, ( struct sockaddr* )&server_address, sizeof( server_address ) ) < 0 )
    {
        printf("connection failed\n");
    }
    else
    {
        const char *oob_data = "abc";
        const char *normal_data = "123";
        send(sockfd, normal_data, strlen(normal_data), 0);
        send(sockfd, oob_data, strlen(oob_data), MSG_OOB);
        send(sockfd, normal_data, strlen(normal_data), 0);
    }
    close(sockfd);
    return 0;
}
相關文章
相關標籤/搜索