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.....
原文地址:https://www.cnblogs.com/vczf/p/14459550.html