zoukankan      html  css  js  c++  java
  • 01Linux网络编程基础 ---- socket连接

    创建 socket

     #include <sys/types.h>          /* See NOTES */
     #include <sys/socket.h>
    
     int socket(int domain, int type, int protocol);

    domain:使用哪个协议簇,PF_UNIX: UNIX本地域协议族 PF_INET: TCP/IPv4协议族 PF_INET6: TCP/IPv6协议族

    type:指定服务类型。TCP:使用SOCK_STREAM(流服务);UDP:使用SOCK_UGRAM(数据报)

    protocol:在前两个确定的情况下,选择一个具体的协议,一般都是0,表示使用默认协议。

    return:成功返回一个socket文件描述符,失败则返回-1并设置errno。

    命名 socket

    #include <sys/socket.h>
    
    int bind(int socket, const struct sockaddr *address, socklen_t address_len);

    所谓命名,就是用bind来给socket绑定地址。

    地址:sockaddrsockaddr_in大小一致,sockaddr端口和IP地址融合在一起了,后者(sockaddr_in)是前者(sockaddr)的细化。

    include <netinet/in.h>  
      
    struct sockaddr {  
        unsigned short    sa_family;    // 2 bytes address family, AF_xxx  
        char              sa_data[14];     // 14 bytes of protocol address  
    };  
      
    // IPv4 AF_INET sockets:  
      
    struct sockaddr_in {  
        short            sin_family;       // 2 bytes e.g. AF_INET, AF_INET6  
        unsigned short   sin_port;    // 2 bytes e.g. htons(3490)  
        struct in_addr   sin_addr;     // 4 bytes see struct in_addr, below  
        char             sin_zero[8];     // 8 bytes zero this if you want to  
    };  
      
    struct in_addr {  
        unsigned long s_addr;          // 4 bytes load with inet_pton()  
    };  

    return:成功返回0,失败则返回-1并设置errno。

    监听 socket

    #include <sys/socket.h>
    
    int listen(int socket, int backlog);

    socket:被监听的socket文件描述符

    backlog:指定内核监听队列的最大长度,如果超过这个值,将不接受新的连接,客户端会收到ECONNREFUSED错误信息,在内核2.2版本之前,backlog = 连接状态(ESTABLISH)+ 半连接状态(SYN_RCVD),但是内核2.2版本之后等于完全连接状态的socket的上限。socket被接受连接后,将从队列中取出,也就是accept。

    return:成功返回0,失败则返回-1并设置errno。

    接受连接 socket

    #include <sys/socket.h>
    
    int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);

    socket:被监听的socket文件描述符。

    address:用来获取被接受连接的远端socket地址。

    address_len:指定socket地址的长度。

    return:成功返回客户端的socket,失败则返回-1并设置errno。

    demo

    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <signal.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <stdio.h>
    #include <string.h>
    
    static bool stop = false;
    static void handle_term( int sig )
    {
        stop = true;
    }
    
    int main( int argc, char* argv[] )
    {
        signal( SIGTERM, handle_term );
    
        if( argc <= 3 )
        {
            printf( "usage: %s ip_address port_number backlog
    ", basename( argv[0] ) );
            return 1;
        }
        const char* ip = argv[1];
        int port = atoi( argv[2] );
        int backlog = atoi( argv[3] );
    
        // 1.创建socket
        // int domanin: 协议族: PF_UNIX: UNIX本地域协议族 PF_INET: TCP/IPv4协议族 PF_INET6: TCP/IPv6协议族
        // int type: SOCK_STREAM(流服务):TCP SOCK_UGRAM(数据报):UDP
        int sock = socket( PF_INET, SOCK_STREAM, 0 );
        assert( sock >= 0 );
    
        // 2.确定socket地址
        struct sockaddr_in address;
        bzero( &address, sizeof( address ) );
        // 地址族:AF_UNIX: UNIX本地域协议族 AF_INET: TCP/IPv4协议族 AF_INET6: TCP/IPv6协议族
        address.sin_family = AF_INET;
        inet_pton( AF_INET, ip, &address.sin_addr );
        // 转换为网络字节序:大段
        address.sin_port = htons( port );
    
        // 3.命名socket
        int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) );
        assert( ret != -1 );
    
        // 4.监听socket
        ret = listen( sock, backlog );
        assert( ret != -1 );
    
        while ( ! stop )
        {
            sleep( 1 );
        }
    
        close( sock );
        return 0;
    }

     执行

    ./5-3testlisten 10.120.225.64 12345 5 # 监听12345 backlog使用5
    telnet 10.120.225.64 12345 & 
    netstat -nt | grep 12345

    结果

    netstat -nt | grep 12345
    tcp        0      0 10.120.225.64:12345     10.143.44.169:63208     SYN_RECV    
    tcp        0      0 10.120.225.64:12345     10.120.225.64:52750     SYN_RECV    
    tcp        0      0 10.120.225.64:52750     10.120.225.64:12345     ESTABLISHED 
    tcp        0      0 10.120.225.64:12345     10.120.225.64:52746     ESTABLISHED 
    tcp        0      0 10.120.225.64:52746     10.120.225.64:12345     ESTABLISHED 
    tcp        0      0 10.120.225.64:52748     10.120.225.64:12345     ESTABLISHED   
    tcp        0      0 10.120.225.64:52745     10.120.225.64:12345     ESTABLISHED 
    tcp        0      0 10.120.225.64:12345     10.120.225.64:52745     ESTABLISHED 

     demo2:添加accept

    while ( ! stop )
        {
            struct sockaddr_in client;
            socklen_t client_addrlength = sizeof( client );
            printf("bloack wait for accept client.....
    ");
            int connfd = accept( sock, ( struct sockaddr* )&client, &client_addrlength );
            if (connfd < 0) {
                printf( "errno is: %d
    ", errno );
            } else {
                char remote[INET_ADDRSTRLEN ];
                // 将二进制整数地址转为点分字符串形式,结果存在remote,INET_ADDRSTRLEN:16 IPV4地址大小
                // 成功返回指向remote的地址,失败则返回NULL
                const char* ptr = inet_ntop( AF_INET, &client.sin_addr, remote, INET_ADDRSTRLEN );
                // 将网络字节序转为主机字节序,网络字节序是大端,
                int port = ntohs( client.sin_port );
                printf( "connected with ip: %s and port: %d
    ", ptr, port);
                printf( "remote: %p and ptr: %p
    ", remote, ptr);
                close(connfd);
            }
            sleep( 1 );
        }

    结果:

    [zf@localhost 5]$ ./5-3testlisten 192.168.1.104 1234 5
    bloack wait for accept client.....
    connected with ip: 192.168.1.103 and port: 57735
    remote: 0x7fffcfb52da0 and ptr: 0x7fffcfb52da0
    bloack wait for accept client.....
  • 相关阅读:
    二叉树相关题目
    二叉树的遍历
    mysql获取某个表中除了某个字段名外的所有字段名
    设计模式之原型模式
    设计模式之工厂方法模式
    设计模式之代理模式
    设计模式之装饰模式
    设计模式之策略模式
    设计模式之简单工厂模式
    Redis的使用及参考代码
  • 原文地址:https://www.cnblogs.com/vczf/p/14459550.html
Copyright © 2011-2022 走看看