zoukankan      html  css  js  c++  java
  • socket编程备忘录

    #include <sys/socket.h>
    int socket(int domain, int type, int protocol);
    socket的三个形参搭配整理如下:
    ------------------------------------------------------------------
    TCP、UDP socket: 最常用的socket,不解释

    tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
    udp_socket = socket(AF_INET, SOCK_DGRAM, 0);

    struct sockaddr_in  inet_addr;
    inet_addr.sin_family      = AF_INET;
    inet_addr.sin_addr.s_addr = inet_addr("192.168.1.1");
    inet_addr.sin_port        = htons(inet_port);

    bind(fd, (struct sockaddr *) &inet_addr, sizeof(inet_addr));

    ------------------------------------------------------------------

    UNIX Domain socket: 进程间通信常用

    unix_socket = socket(AF_LOCAL, SOCK_STREAM, 0); 或者
    unix_socket = socket(AF_LOCAL, SOCK_DGRAM, 0);

    struct sockaddr_un  un_addr;

    unlink("my_file_path");
    un_addr.sun_family = AF_LOCAL;
    strcpy(un_addr.sun_path, "my_file_path");

    bind(fd, (struct sockaddr *) &un_addr, sizeof(un_addr));

    ----------------------------------------------------------------------
    RAW socket: 用来处理IP包,它最多只能触及IP包头,再往下就搞不定了

    inet_raw_fd = socket(AF_INET, SOCK_RAW, my_protocol);
    struct sockaddr_in    inet_addr;


    inet_addr.sin_family = AF_INET;
    inet_addr.sin_addr.s_addr = inet_addr("192.168.1.1");

    int on = 1;  /*  1 用户程序处理IP头,  0 用户程序不处理IP头 */
    setsockopt(inet_raw_fd,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on));

    形参 my_protocol,可选值为下面的任意组合
    IPPROTO_UDP 
    IPPROTO_TCP 
    IPPROTO_ICMP  

    IPPROTO_RAW

    ----------------------------------------------------------------------
    AF_PACKET socket: 用来处理以太网包,它能修改以太网包头

    un_cooked_fd = socket(AF_PACKET, SOCK_RAW, my_protocol); //用户程序处理 以太网头
    cooked_fd = socket(AF_PACKET, SOCK_DGRAM, my_protocol);  //用户程序不处理以太网头

    struct sockaddr_ll ll_addr;

    struct ifreq if_idx;
    strncpy(if_idx.ifr_name, "eth0", IFNAMSIZ-1);
    ioctl(fd, SIOCGIFINDEX, &if_idx);

    ll_addr.sll_family = AF_PACKET;
    ll_addr.sll_protocol = htons(ETH_P_ALL);
    ll_addr.sll_ifindex = if_idx.ifr_ifindex;

    bind(sockfd, (struct sockaddr *)&ll_addr, sizeof(ll_addr)) ;

    形参 my_protocol,可选值为下面的任意组合
    ETH_P_IP
    ETH_P_ARP
    ETH_P_RARP

    ETH_P_ALL

     pingpang_socket.rar   
    -------------------------------------------------------------------------

    NetLink socket: TODO

    ############################################################################
        
    accept 调用前连接夭折:    
          SVR4 实现:    返回错误码
          Berkeley实现: 服务器进程看不到

    服务器fork出来的子进程挂了:
        a.父进程 先前已经close了 connfd
        b.子进程 挂会导致释放 connfd
        c.connfd 描述字释放后,会导致发送 FIN 给客户端
        d.客户发 ACK
        e.客户发 数据 (引发server发RST)
        客户read此时返回(只接受到FIN,返回0,errno "server terminated prematurely" 服务器过早终止)
        f.服务 发 RST(防止主动关闭的一端经历 TIME_WAIT 状态)
        客户 read 此时返回(接受到FIN 和 RST, RST 优先级高,返回,errno "ECONNREAET" 对方复位连接)
        g.客户再发数据 (引发SIGPIPE信号)

            
    服务器主机挂了
        客户发数据
        read 返回错误 完全没响应 ETIMEOUT
        中间路由器判断服务器主机不可达,发目的地不可达的ICMP消息响应,错误 EHOSTUNREACH 或 ENETUNREACH


    服务器主机崩溃后重启
        服务器崩溃后重启,他的TCP丢失了连接信息
        客户发数据
            服务发RST
            客户read 返回错误 ECONNRESET

    daytime 服务器 accept 后 write 后马上 close ??    

      
    从进程到内核传递套接字地址结构有3个函数:bind connect sendto
    他们的形参中都有 *sockaddr 和 结构大小sizeof(serv)
        bind(sockfd,(struct sockaddr *)&serv,sizeof(serv) );

    从内核到进程传递套接字地址结构有4个函数:accept recvfrom getsocketname getpeername
    他们的形参中都有 *sockaddr 和 指向结构大小的整数的“指针”  
        struct sockaddr_un test;
        socklen_t len = sizeof(test);
        getpeername(unixfd,(* sockaddr)&test,&len);
        /* len 可能会变,这时len代表test的写后大小*/

    为何将结构大小由整数改为指向整数的指针呢?
    这样len可以被函数更新
    当函数被调用时,结构大小是一个值(此值告诉内核在写结构时不至于越界),
    当函数返回时,结构大小又是一个结果(它告诉进程,内核在此结构中确切存储了多少信息),
    这种参数类型叫做“值-结果”参数


    客户在读回任何东西之前对服务器写两次,而第一次写就引发了一个RST.(第二次写生成SIGPIPE)
    所用规则是:当一个进程(client)向接受了RST的套接字(server)进行写操作时,内核给该进程(client)
    发一个SIGPIPE信号。此信号的缺省行为就是终止进程(client),所以进程(client)必须捕获它以免被终止

    client不论是捕获了该信号并从信号处理程序返回,还是不理会该信号,client写操作都返回EPIPE错误



    网络编程时可能会遇到的三种情况:
    1 当派生子进程时,必须捕获信号
    2 当捕获信号时,必须处理被中断的系统调用
    3 SIGCHLD的信号处理程序应使用函数waitpid以免留下僵尸进程


    在客户断和服务器可以通信之前,每一方都要指定连接的套接字对:
        本地IP 和 本地端口    
            两端都可以调用bind(通常客户不调,由内核选择,内核选后由getsockname探知)
        远程IP 和 远程端口    
            客户调用connect;服务器端通过accept返回这2个值。
            若accept返回后由新程序来处理,且调用exec来执行,则在新程序中必要时
            调用getpeername来确定客户的IP地址和端口号。(前提是connfd要传给exec)


    关于异构系统socket通信时大端小端问题,常用解决方法:
    1。所有的数值数据作为文本串来传递。当然,保证通讯两主机要有相同的字符集
    2。显示定义所支持数据类型的二进制格式(位数,大端,小端)。远程过程调用(RPC)软件包常用此技术


    拒绝服务型攻击
       当一个服务器正在处理多个客户时,服务器决不能阻塞于只与单个用户相关的函数调用。如果这样的话
    服务器将悬挂并拒绝为所有其他客户提供服务,这叫拒绝服务(denial of service)型攻击。
       可能的解决方法:(a)使用非阻塞I/O模型
              (b)让每个客户由单独的控制线程提供服务(例如,创建子进程或线程来为每个客户提供服务)
              (c)对I/O操作设置超时

    有3种方法给套接字上的I/O操作设置超时
    1. 调用alarm(),这涉及到信号处理,可能与进程中其他已有的alarm调用冲突
    2. 使用select阻塞在等待I/O上,select内部有一个时间限制,以此来代替在read或write调用上的阻塞
    3. 使用新的SO_RECVTIMEO SO_SNDTIMEO套接字选项,但并不是所有实现都支持这两个套接字选项。


    ###############################################################################################

    #include <sys/socket.h>
    ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
    ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);

    这连个函数和标准的read和write函数很相似,前三个参数意义和read write 相同。
    只是多了一个附加的参数flags (0 或者一些宏的逻辑或)
                   recv    send
    MSG_DONTROUTE           Y
    MSG_DONTWAIT    Y       Y
    MSG_OOB         Y       Y
    MSG_PEEK        Y
    MSG_WAITTALL    Y

    参考:

    http://blog.chinaunix.net/uid-24148050-id-3161566.html

  • 相关阅读:
    toj 2819 Travel
    toj 2807 Number Sort
    zoj 2818 Prairie dogs IV
    zoj 1276 Optimal Array Multiplication Sequence
    toj 2802 Tom's Game
    toj 2798 Farey Sequence
    toj 2815 Searching Problem
    toj 2806 Replace Words
    toj 2794 Bus
    css截取字符
  • 原文地址:https://www.cnblogs.com/yaozhongxiao/p/3020495.html
Copyright © 2011-2022 走看看