• Linux网络编程初步


    Linux网络编程初步

    主机字节序和网络字节序

    32位置机器一次性能装载4字节。那么四字节在内存的顺序影响它被累加器装载成的整数的值。主要分为大端和小端。

    大端字节序是一个整数高位字节(2331bit)存在内存的低处,低字节(07 bit) 存储在内存的高地址处。小端相反。

    现代PC大多是小端序。小端就称为主机字节序。JVM采用大端(网络字节序)。下面是检测大端小段的案例

    我的linux机子是小端序了。。。

        union {
            short value;
            char union_bytes[sizeof( short ) ];
        } test;
        test.value = 0x0102;
        printf("%d %d
    ", 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下提供了四个函数来完成主机字节序和网络字节序的转换。

    #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 => htonl

    一个网络编程的例子

    服务端:

    #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
    ", 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
    ", errno);
        }
        else
        {
            char buffer[ BUF_SIZE ];
    
            memset( buffer, '', BUF_SIZE );
            ret = recv( connfd, buffer, BUF_SIZE - 1, 0 );
            printf("[%d: %s]
    ", ret, buffer);
    
            memset( buffer, '', BUF_SIZE );
            ret = recv( connfd, buffer, BUF_SIZE - 1, MSG_OOB );
            printf("[%d: %s]
    ", ret, buffer);
    
            memset( buffer, '', BUF_SIZE );
            ret = recv( connfd, buffer, BUF_SIZE - 1, 0 );
            printf("[%d: %s]
    ", 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
    ", 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
    ", 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
    ");
        }
        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;
    }
    
  • 相关阅读:
    对流程和规范的思考
    我的一小时面试指南
    安全扫描工具nikto简单使用
    测试的角色
    测试的窘境
    关于重连测试的一点研究
    ETCD高可用特性学习
    Cgroup和Namespace在测试中的使用(下)
    单循环列表的删除前驱结点
    指针常量字符串
  • 原文地址:https://www.cnblogs.com/Q1143316492/p/10459510.html
Copyright © 2020-2023  润新知