zoukankan      html  css  js  c++  java
  • 网络通信 --> socket通信

    socket通信

      socket是应用层与TCP/IP协议族通信的中间软件抽象层,是一组接口。工作原理如下:

      具体过程:服务器端先初始化socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

     

    socket属性

    1.创建套接字

      套接字的特性由三个属性确定:域(domain), 类型(type)和协议(protocol)。

    int socket(int domain, int type, int protocol);

      domain:指定socket的类型,一般为AF_INET;

      type:是SOCK_STREAM 或SOCK_DGRAM,分别表示TCP连接和UDP连接;

      protocol :通常赋值"0"。

    socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。

    2.命名套接字

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    //my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;
    //addrlen常被设置为sizeof(struct sockaddr)。

      返回值:0表示成功;-1表示遇到错误,并将errno置为相应的错误号。

      端口号 : 一般不要置为小于1024的值,因为1~1024是保留端口号 ,可使用大于1024中任何一个没有被占用的端口号。

      addr的赋值如下:实现自动获得本机IP地址和随机获取一个没有被占用的端口号。

    my_addr.sin_port = 0;                   /* 系统随机选择一个未被使用的端口号 */
    my_addr.sin_addr.s_addr = INADDR_ANY;   /* 填入本机IP地址 */ 

    3.套接字地址结构

       套接字地址由结构sockaddr_in来指定,在头文件 <netinet/in.h> 中定义。

       第一个结构

    struct sockaddr {
         unsigned short  sa_family;   /* 地址族, AF_xxx */
         char  sa_data[14];           /* 14 字节的协议地址 */
    };
    
      sa_family:一般为AF_INET;
      sa_data :包含该socket的IP地址和端口号。

      
      第二种结构:
    struct sockaddr_in {
        short int sin_      family;      /* 地址族 */
        unsigned short int  sin_port;    /* 端口号 */
        struct in_addr      sin_addr;    /* IP地址 */
        unsigned char       sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大小 */
    };

      sin_family :通常被赋AF_INET;

      sin_port和 sin_addr :转换成为网络字节优先顺序 。

      sin_zero :用来将sockaddr_in结构填充到与struct sockaddr同样的长度,应该用bzero()或memset()函数将其置为零。

      指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,如果一个函数所需参数类型是sockaddr时,可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向sockaddr的指针;或者相反。

      IP地址结构 in_addr 被定义为:

    struct in_addr{
          unsigned long int  s_addr;
    };

    4.创建队列

    int listen(int sockfd, int backlog); 
    //backlog指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()它们

      backlog:队列中等待服务的请求数目,系统缺省值为20,常用值是5。

      返回值:-1表示遇到错误,errno被置为相应的错误码。

     

    5.阻塞接收

      当某个客户端试图与服务器监听的端口连接时,该连接请求将排队等待服务器 accept()它 。

    int accept(int sockfd, void *addr, int *addrlen); 
    //addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求);
    //addrten通常为一个指向值为sizeof(struct sockaddr_in)的整型指针变量。

      返回值:-1表示错误,并且设置相应的errno值。

     

    6.请求连接

      connect()函数用来与远端服务器建立一个TCP连接。

    int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); 
    //sockfd是目的服务器的sockt描述符;serv_addr是包含目的机IP地址和端口号的指针。

      返回值:-1表示遇到错误,并且设置相应的errno值。

     

    7.数据传输

      send()和recv()——数据传输

    int send(int sockfd, const void *msg, int len, int flags); 
    //sockfd是你想用来传输数据的socket描述符,msg是一个指向要发送数据的指针,Len是以字节为单位的数据的长度。flags一般情况下置为0。

      返回值:返回实际发送出的字节数。当send()返回值与len不匹配时,应该对这种情况进行处理。

    int recv(int sockfd,void *buf,int len,unsigned int flags);
    //sockfd是接受数据的socket描述符;buf 是存放接收数据的缓冲区;len是缓冲的长度。Flags也被置为0。

      返回值:返回实际上接收的字节数,或当出现错误时,返回-1并置相应的errno值。

     

    socket使用

    例一server端:

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<errno.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    
    #define MAXLINE 4096
    
    int main( int argc, char** argv )
    {
        int listenfd, connfd;
        struct sockaddr_in servaddr;
        char buff[4096];
        int n;
    
        if( ( listenfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
        {
            printf( "create socket error: %s(errno: %d)
    ",strerror( errno ),errno );
            exit( 0 );
        }
    
        memset( &servaddr, 0, sizeof( servaddr ) );
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
        servaddr.sin_port = htons( 6666 );
    
        if( bind( listenfd, ( struct sockaddr* )&servaddr, sizeof( servaddr ) ) == -1 )
        {
            printf( "bind socket error: %s(errno: %d)
    ",strerror( errno ),errno );
            exit( 0 );
        }
    
        if( listen( listenfd, 10 ) == -1 )
        {
            printf( "listen socket error: %s(errno: %d)
    ",strerror( errno ),errno );
            exit( 0 );
        }
    
        printf( "======waiting for client's request======
    " );
        while( 1 )
        {
            if( ( connfd = accept( listenfd, ( struct sockaddr* )NULL, NULL ) ) == -1 )
            {
                printf( "accept socket error: %s(errno: %d)",strerror( errno ),errno );
                continue;
            }
            n = recv( connfd, buff, MAXLINE, 0 );
            buff[n] = '';
            printf( "recv msg from client: %s
    ", buff );
            close( connfd );
        }
    
        close( listenfd );
    }

    client端:

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<errno.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    
    #define MAXLINE 4096
    
    int main( int argc, char** argv )
    {
        int sockfd, n;
        char recvline[4096], sendline[4096];
        struct sockaddr_in servaddr;
    #if 0
        if( argc != 2 )
        {
            printf( "usage: ./client <ipaddress>
    " );
            exit( 0 );
        }
    #endif
        if( ( sockfd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
        {
            printf( "create socket error: %s(errno: %d)
    ", strerror( errno ),errno );
            exit( 0 );
        }
    
        memset( &servaddr, 0, sizeof( servaddr ) );
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = inet_addr( "109.123.123.36" );
        servaddr.sin_port = htons( 6666 );
    
    #if 0
        if( inet_pton( AF_INET, argv[1], &servaddr.sin_addr ) <= 0 )
        {
            printf( "inet_pton error for %s
    ",argv[1] );
            exit( 0 );
        }
    #endif
    
        if( connect( sockfd, ( struct sockaddr* )&servaddr, sizeof( servaddr ) ) < 0 )
        {
            printf( "connect error: %s(errno: %d)
    ",strerror( errno ),errno );
            exit( 0 );
        }
    
        printf( "send msg to server: 
    " );
        fgets( sendline, 4096, stdin );
        if( send( sockfd, sendline, strlen( sendline ), 0 ) < 0 )
        {
            printf( "send msg error: %s(errno: %d)
    ", strerror( errno ), errno );
            exit( 0 );
        }
    
        close( sockfd );
        exit( 0 );
    }

    例二:server端:

    //s_unix.c  
    #include <stdio.h>  
    #include <sys/types.h>  
    #include <sys/socket.h>  
    #include <sys/un.h>   
    #define UNIX_DOMAIN "/tmp/UNIX.domain"  
    int main(void)  
    {  
        socklen_t clt_addr_len;  
        int listen_fd;  
        int com_fd;  
        int ret;  
        int i;  
        static char recv_buf[1024];   
        int len;  
        struct sockaddr_un clt_addr;  
        struct sockaddr_un srv_addr;  
        listen_fd=socket(PF_UNIX,SOCK_STREAM,0);  
        if(listen_fd<0)  
        {  
            perror("cannot create communication socket");  
            return 1;  
        }    
          
        //set server addr_param  
        srv_addr.sun_family=AF_UNIX;  
        strncpy(srv_addr.sun_path,UNIX_DOMAIN,sizeof(srv_addr.sun_path)-1);  
        unlink(UNIX_DOMAIN);  
        //bind sockfd & addr  
        ret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));  
        if(ret==-1)  
        {  
            perror("cannot bind server socket");  
            close(listen_fd);  
            unlink(UNIX_DOMAIN);  
            return 1;  
        }  
        //listen sockfd   
        ret=listen(listen_fd,1);  
        if(ret==-1)  
        {  
            perror("cannot listen the client connect request");  
            close(listen_fd);  
            unlink(UNIX_DOMAIN);  
            return 1;  
        }  
        //have connect request use accept  
        len=sizeof(clt_addr);  
        com_fd=accept(listen_fd,(struct sockaddr*)&clt_addr,&len);  
        if(com_fd<0)  
        {  
            perror("cannot accept client connect request");  
            close(listen_fd);  
            unlink(UNIX_DOMAIN);  
           return 1;  
        }  
        //read and printf sent client info  
        printf("
    =====info=====
    ");  
        for(i=0;i<4;i++)  
        {  
            memset(recv_buf,0,1024);  
            int num=read(com_fd,recv_buf,sizeof(recv_buf));  
            printf("Message from client (%d)) :%s
    ",num,recv_buf);    
        }  
        close(com_fd);  
        close(listen_fd);  
        unlink(UNIX_DOMAIN);  
        return 0;  
    } 

    client端

    //c_unix.c  
    #include <stdio.h>  
    #include <sys/types.h>  
    #include <sys/socket.h>  
    #include <sys/un.h>  
    #define UNIX_DOMAIN "/tmp/UNIX.domain"  
    int main(void)  
    {  
    int connect_fd;  
    int ret;  
    char snd_buf[1024];  
    int i;  
    static struct sockaddr_un srv_addr;  
    //creat unix socket  
    connect_fd=socket(PF_UNIX,SOCK_STREAM,0);  
    if(connect_fd<0)  
    {  
        perror("cannot create communication socket");  
        return 1;  
    }     
    srv_addr.sun_family=AF_UNIX;  
    strcpy(srv_addr.sun_path,UNIX_DOMAIN);  
    //connect server  
    ret=connect(connect_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));  
    if(ret==-1)  
    {  
        perror("cannot connect to the server");  
        close(connect_fd);  
        return 1;  
    }  
    memset(snd_buf,0,1024);  
    strcpy(snd_buf,"message from client");  
    //send info server  
    for(i=0;i<4;i++)  
        write(connect_fd,snd_buf,sizeof(snd_buf));  
    close(connect_fd);  
    return 0;  
    }  
  • 相关阅读:
    PC software
    pdf.js查看器 在线预览 office文件、图片、文本文件
    核算两个时间之间时长
    Flink sql 之 join 与 StreamPhysicalJoinRule (源码解析)
    Flink sql 之 TopN 与 StreamPhysicalRankRule (源码解析)
    Flink Sql 之 Calcite Volcano优化器(源码解析)
    Keepalive高可用部署
    Keepalive配置文件
    Erlang环境安装
    ZooKeeper集群
  • 原文地址:https://www.cnblogs.com/jeakeven/p/4763881.html
Copyright © 2011-2022 走看看