精华内容
下载资源
问答
  • 使用百度的socketUtil能连接上,但拿到数据,不是400就是超时idea中Javaweb项目写main方法测试相关代码public class SocketUtils {private static Logger logger = Logger.getLogger(SocketUtils.class);/*** 发送...

    使用百度的socketUtil能连接上,但拿不到数据,不是400就是超时

    idea中Javaweb项目写main方法测试

    相关代码

    public class SocketUtils {

    private static Logger logger = Logger.getLogger(SocketUtils.class);

    /**

    * 发送socket请求

    * @param clientIp

    * @param clientPort

    * @param msg

    * @return

    */

    public static synchronized String tcpPost(String clientIp,String clientPort,String msg){

    String rs = "";

    if(clientIp==null||"".equals(clientIp)||clientPort==null||"".equals(clientPort)){

    logger.error("Ip或端口不存在...");

    return null;

    }

    int clientPortInt = Integer.parseInt(clientPort);

    logger.info("clientIp:"+clientIp+" clientPort:"+clientPort);

    Socket s = null;

    OutputStream out = null;

    InputStream in = null;

    try {

    s = new Socket(clientIp, clientPortInt);

    s.setSendBufferSize(4096);

    s.setTcpNoDelay(true);

    s.setSoTimeout(60*1000);

    s.setKeepAlive(true);

    //out = s.getOutputStream();

    in = s.getInputStream();

    //准备报文msg

    //logger.info("准备发送报文:"+msg);

    //out.write(msg.getBytes("GBK"));

    //out.flush();

    byte[] rsByte = readStream(in);

    if(rsByte!=null){

    rs = new String(rsByte, "GBK");

    }

    } catch (Exception e) {

    logger.error("tcpPost发送请求异常:"+e.getMessage());

    }finally{

    logger.info("tcpPost(rs):"+rs);

    try {

    if(out!=null){

    out.close();

    out = null;

    }

    if(in!=null){

    in.close();

    in = null;

    }

    if(s!=null){

    s.close();

    s = null;

    }

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    return rs;

    }

    /**

    * 读取输入流

    * @param in

    * @return

    */

    public static byte[] readStream(InputStream in){

    if(in==null){

    return null;

    }

    byte[] b = null;

    ByteArrayOutputStream outSteam = null;

    try {

    byte[] buffer = new byte[1024];

    outSteam = new ByteArrayOutputStream();

    int len = -1;

    while ((len = in.read(buffer)) != -1) {

    outSteam.write(buffer, 0, len);

    }

    b = outSteam.toByteArray();

    } catch (IOException e) {

    logger.error("读取流信息异常"+e);

    e.printStackTrace();

    } finally{

    try {

    if(outSteam!=null){

    outSteam.close();

    outSteam = null;

    }

    if(in!=null){

    in.close();

    in = null;

    }

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    return b;

    }

    }

    读取流信息异常java.net.SocketTimeoutException: Read timed out或者tcpPost(rs):400 Bad Request然后一段400的html代码

    展开全文
  • 继上一篇介绍了数据包的接收过程后,本文将介绍在Linux系统中,数据包是如何一步一步从应用程序到网卡并最终发送出去的。如果英文没有问题,强烈建议阅读后面参考里的文章,里面介绍的更详细。本文只讨论以太网的...

    0019fd20dce5a44e45f18ca2850ee0b9.png

    继上一篇介绍了数据包的接收过程后,本文将介绍在Linux系统中,数据包是如何一步一步从应用程序到网卡并最终发送出去的。

    如果英文没有问题,强烈建议阅读后面参考里的文章,里面介绍的更详细。

    本文只讨论以太网的物理网卡,并且以一个UDP包的发送过程作为示例,由于本人对协议栈的代码不熟,有些地方可能理解有误,欢迎指正

    socket层

    +-------------+

    | Application |

    +-------------+

    |

    |

    +------------------------------------------+

    | socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) |

    +------------------------------------------+

    |

    |

    +-------------------+

    | sendto(sock, ...) |

    +-------------------+

    |

    |

    +--------------+

    | inet_sendmsg |

    +--------------+

    |

    |

    +---------------+

    | inet_autobind |

    +---------------+

    |

    |

    +-----------+

    | UDP layer |

    +-----------+

    socket(...): 创建一个socket结构体,并初始化相应的操作函数,由于我们定义的是UDP的socket,所以里面存放的都是跟UDP相关的函数

    sendto(sock, ...): 应用层的程序(Application)调用该函数开始发送数据包,该函数数会调用后面的inet_sendmsg

    inet_sendmsg: 该函数主要是检查当前socket有没有绑定源端口,如果没有的话,调用inet_autobind分配一个,然后调用UDP层的函数

    inet_autobind: 该函数会调用socket上绑定的get_port函数获取一个可用的端口,由于该socket是UDP的socket,所以get_port函数会调到UDP代码里面的相应函数。

    UDP层

    |

    |

    +-------------+

    | udp_sendmsg |

    +-------------+

    |

    |

    +----------------------+

    | ip_route_output_flow |

    +----------------------+

    |

    |

    +-------------+

    | ip_make_skb |

    +-------------+

    |

    |

    +------------------------+

    | udp_send_skb(skb, fl4) |

    +------------------------+

    |

    |

    +----------+

    | IP layer |

    +----------+

    udp_sendmsg: udp模块发送数据包的入口,该函数较长,在该函数中会先调用ip_route_output_flow获取路由信息(主要包括源IP和网卡),然后调用ip_make_skb构造skb结构体,***将网卡的信息和该skb关联。

    ip_route_output_flow: 该函数会根据路由表和目的IP,找到这个数据包应该从哪个设备发送出去,如果该socket没有绑定源IP,该函数还会根据路由表找到一个最合适的源IP给它。 如果该socket已经绑定了源IP,但根据路由表,从这个源IP对应的网卡没法到达目的地址,则该包会被丢弃,于是数据发送失败,sendto函数将返回错误。该函数***会将找到的设备和源IP塞进flowi4结构体并返回给udp_sendmsg

    ip_make_skb: 该函数的功能是构造skb包,构造好的skb包里面已经分配了IP包头,并且初始化了部分信息(IP包头的源IP就在这里被设置进去),同时该函数会调用__ip_append_dat,如果需要分片的话,会在__ip_append_data函数中进行分片,同时还会在该函数中检查socket的send buffer是否已经用光,如果被用光的话,返回ENOBUFS

    udp_send_skb(skb, fl4) 主要是往skb里面填充UDP的包头,同时处理checksum,然后调用IP层的相应函数。

    IP层

    |

    |

    +-------------+

    | ip_send_skb |

    +-------------+

    |

    |

    +-------------------+       +-------------------+       +---------------+

    | __ip_local_out_sk |------>| NF_INET_LOCAL_OUT |------>| dst_output_sk |

    +-------------------+       +-------------------+       +---------------+

    |

    |

    +------------------+        +----------------------+       +-----------+

    | ip_finish_output |

    +------------------+        +----------------------+       +-----------+

    |

    |

    +-------------------+      +------------------+       +----------------------+

    | ip_finish_output2 |----->| dst_neigh_output |------>| neigh_resolve_output |

    +-------------------+      +------------------+       +----------------------+

    |

    |

    +----------------+

    | dev_queue_xmit |

    +----------------+

    ip_send_skb: IP模块发送数据包的入口,该函数只是简单的调用一下后面的函数

    __ip_local_out_sk: 设置IP报文头的长度和checksum,然后调用下面netfilter的钩子

    NF_INET_LOCAL_OUT: netfilter的钩子,可以通过iptables来配置怎么处理该数据包,如果该数据包没被丢弃,则继续往下走

    dst_output_sk: 该函数根据skb里面的信息,调用相应的output函数,在我们UDP IPv4这种情况下,会调用ip_output

    ip_output: 将上面udp_sendmsg得到的网卡信息写入skb,然后调用NF_INET_POST_ROUTING的钩子

    NF_INET_POST_ROUTING: 在这里,用户有可能配置了SNAT,从而导致该skb的路由信息发生变化

    ip_finish_output: 这里会判断经过了上一步后,路由信息是否发生变化,如果发生变化的话,需要重新调用dst_output_sk(重新调用这个函数时,可能就不会再走到ip_output,而是走到被netfilter指定的output函数里,这里有可能是xfrm4_transport_output),否则往下走

    ip_finish_output2: 根据目的IP到路由表里面找到下一跳(nexthop)的地址,然后调用__ipv4_neigh_lookup_noref去arp表里面找下一跳的neigh信息,没找到的话会调用__neigh_create构造一个空的neigh结构体

    dst_neigh_output: 在该函数中,如果上一步ip_finish_output2没得到neigh信息,那么将会走到函数neigh_resolve_output中,否则直接调用neigh_hh_output,在该函数中,会将neigh信息里面的mac地址填到skb中,然后调用dev_queue_xmit发送数据包

    neigh_resolve_output: 该函数里面会发送arp请求,得到下一跳的mac地址,然后将mac地址填到skb中并调用dev_queue_xmit

    netdevice子系统

    |

    |

    +----------------+

    +----------------| dev_queue_xmit |

    |                +----------------+

    |                       |

    |                       |

    |                       ↓

    |              +-----------------+

    |              | Traffic Control |

    |              +-----------------+

    | loopback              |

    |   or+--------------------------------------------------------------+

    | IP tunnels            ↓                                                              |

    |                       ↓                                                              |

    |            +---------------------+  Failed   +----------------------+         +---------------+

    +----------->| dev_hard_start_xmit |---------->| raise NET_TX_SOFTIRQ |- - - - >| net_tx_action |

    +---------------------+           +----------------------+         +---------------+

    |

    +----------------------------------+

    |                                  |

    ↓                                  ↓

    +----------------+              +------------------------+

    | ndo_start_xmit |              | packet taps(AF_PACKET) |

    +----------------+              +------------------------+

    dev_queue_xmit: netdevice子系统的入口函数,在该函数中,会先获取设备对应的qdisc,如果没有的话(如loopback或者IP tunnels),就直接调用dev_hard_start_xmit,否则数据包将经过Traffic Control模块进行处理

    Traffic Control: 这里主要是进行一些过滤和优先级处理,在这里,如果队列满了的话,数据包会被丢掉,详情请参考文档,这步完成后也会走到dev_hard_start_xmit

    dev_hard_start_xmit: 该函数中,首先是拷贝一份skb给“packet taps”,tcpdump就是从这里得到数据的,然后调用ndo_start_xmit。如果dev_hard_start_xmit返回错误的话(大部分情况可能是NETDEV_TX_BUSY),调用它的函数会把skb放到一个地方,然后抛出软中断NET_TX_SOFTIRQ,交给软中断处理程序net_tx_action稍后重试(如果是loopback或者IP tunnels的话,失败后不会有重试的逻辑)

    ndo_start_xmit: 这是一个函数指针,会指向具体驱动发送数据的函数

    Device Driver

    ndo_start_xmit会绑定到具体网卡驱动的相应函数,到这步之后,就归网卡驱动管了,不同的网卡驱动有不同的处理方式,这里不做详细介绍,其大概流程如下:

    将skb放入网卡自己的发送队列

    通知网卡发送数据包

    网卡发送完成后发送中断给CPU

    收到中断后进行skb的清理工作

    在网卡驱动发送数据***程中,会有一些地方需要和netdevice子系统打交道,比如网卡的队列满了,需要告诉上层不要再发了,等队列有空闲的时候,再通知上层接着发数据。

    其它

    SO_SNDBUF: 从上面的流程中可以看出来,对于UDP来说,没有一个对应send buffer存在,SO_SNDBUF只是一个限制,当这个socket分配的skb占用的内存超过这个值的时候,会返回ENOBUFS,所以说只要不出现ENOBUFS错误,把这个值调大没有意义。从sendto函数的帮助文件里面看到这样一句话:(Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.)。这里的device queue应该指的是Traffic Control里面的queue,说明在linux里面,默认的SO_SNDBUF值已经够queue用了,疑问的地方是,queue的长度和个数是可以配置的,如果配置太大的话,按道理应该有可能会出现ENOBUFS的情况。

    txqueuelen: 很多地方都说这个是控制qdisc里queue的长度的,但貌似只是部分类型的qdisc用了该配置,如linux默认的pfifo_fast。

    hardware RX: 一般网卡都有一个自己的ring queue,这个queue的大小可以通过ethtool来配置,当驱动收到发送请求时,一般是放到这个queue里面,然后通知网卡发送数据,当这个queue满的时候,会给上层调用返回NETDEV_TX_BUSY

    packet taps(AF_PACKET): 当***次发送数据包和重试发送数据包时,都会经过这里,如果发生重试的情况的话,不确定tcpdump是否会抓到两次包,按道理应该不会,可能是我哪里没看懂

    参考

    【编辑推荐】

    【责任编辑:枯木 TEL:(010)68476606】

    点赞 0

    展开全文
  • 作者:Godbach日期:2009/09/01一、构造数据包简析这里并详细介绍如何在内核中构造数据包,下文如有需要会在适当的位置进行分析。这里简单的分析讲一下内核态基于Netfilter框架构造数据包的方式。内核中可以用到的...

    本文欢迎自由转载,但请标明出处,并保证本文的完整性。

    作者:Godbach

    日期:2009/09/01

    一、构造数据包简析

    这里并不详细介绍如何在内核中构造数据包,下文如有需要会在适当的位置进行分析。这里简单的分析讲一下内核态基于Netfilter框架构造数据包的方式。

    内核中可以用到的构造数据包的方式,个人认为可以分为两种。

    其一,我们直接用alloc_skb申请一个skb结构体,然后根据实际的应用填充不同的成员,或者基于当前数据包的skb,调用skb_copy_expand()函数等新申请一个nskb,并且拷贝skb的内容。

    其二,也是个人比较常用的,就是直接在先前接收到的数据包skb上作修改,主要有源IP、目IP,如果是TCP/UDP协议的话,还有源端口目的端口号。总之,就是根据自己的需求去调整数据包的相关成员即可。

    通常,这两种方式最终可能都要涉及到重新计算各个部分的校验和,这也是必须的。

    二、如何发送构造的数据包

    承接上文,数据包已经构造完毕,下一步关键就是如何发送数据包了。个人这里总结的有两种方法。

    方法一,就是让数据包接着按照Netfilter的流程进行传输。因为数据包的一些内容已经被更改,尤其是当源IP和目的IP被更改,主要是交换的情况下,是需要确保有路由可查的。

    NF框架中查路由的位置一是在PREROUTING之后,而是在LOCALOUT之后。又由于这里是需要将数据包从本地发送出去。因此,可以考虑让修改后的数据包从LOCALOUT点发出。

    内核代码中有这种方式的典型体现。本文涉及的相关内核代码的版本都是2.6.18.3。源文件为ipt_REJECT.c,函数send_reset用于往当前接收到数据包的源IP上发送RST包,整个函数涉及了数据包的构造和发送,这里一起做个简单分析。

    /* Send RST reply */

    static void send_reset(struct sk_buff *oldskb, int hook)

    {

    struct sk_buff *nskb;

    struct iphdr *iph = oldskb->nh.iph;

    struct tcphdr _otcph, *oth, *tcph;

    struct rtable *rt;

    u_int16_t tmp_port;

    u_int32_t tmp_addr;

    int needs_ack;

    int hh_len;

    /* 判断是否是分片包*/

    if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))

    return;

    /*得到TCP头部指针*/

    oth = skb_header_pointer(oldskb, oldskb->nh.iph->ihl * 4,

    sizeof(_otcph), &_otcph);

    if (oth == NULL)

    return;

    /* 当期收到的包就是RST包,就不用再发送RST包了*/

    if (oth->rst)

    return;

    /*检查数据包的校验和是否正确*/

    if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP))

    return;

    /*这一步比较关键,做的就是更新路由的工作。该函数的主要工作就是将当前数据包的源IP当做路由的目的IP,同时考虑数据包的目的IP,得到去往该源IP的路由*/

    if ((rt = route_reverse(oldskb, oth, hook)) == NULL)

    return;

    hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);

    /* 拷贝当前的oldskb,包括skb结构体和数据部分。这就是我们上面提到的构造数据包的第一种方式*/

    nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),

    GFP_ATOMIC);

    if (!nskb) {

    dst_release(&rt->u.dst);

    return;

    }

    /*因为是拷贝的oldskb,这里不需要再引用了,因此释放对该路由项的引用*/

    dst_release(nskb->dst);

    /*将新构造数据包引用的路由指向上面由route_reverse函数返回的新的路由项 */

    nskb->dst = &rt->u.dst;

    /* 清除nskb中拷贝过来的oldskb中链接跟踪相关的内容*/

    nf_reset(nskb);

    nskb->nfmark = 0;

    skb_init_secmark(nskb);

    /*以下就是构造数据包的实际数据部分。如果我们将这里不为nskb新申请缓冲区,而直接指向oldskb的缓冲区,就使我们上面提到的第二种构造数据包的方法。*/

    /*获取nskb的tcp header*/

    tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);

    /*交换源和目的IP */

    tmp_addr = nskb->nh.iph->saddr;

    nskb->nh.iph->saddr = nskb->nh.iph->daddr;

    nskb->nh.iph->daddr = tmp_addr;

    /*交换源和目的端口 */

    tmp_port = tcph->source;

    tcph->source = tcph->dest;

    tcph->dest = tmp_port;

    /*重置TCP头部的长度,并修改IP头部中记录的数据包的总长度。因为这里是发送RST报文,只需要有TCP的头部,不需要TCP的数据部分*/

    tcph->doff = sizeof(struct tcphdr)/4;

    skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));

    nskb->nh.iph->tot_len = htons(nskb->len);

    /*重新设置 seq, ack_seq,分两种情况(TCP/IP详解有描述)*/

    if (tcph->ack) { /*原始数据包中ACK标记位置位的情况*/

    needs_ack = 0;

    tcph->seq = oth->ack_seq; /*原始数据包的ack_seq作为nskb的seq*/

    tcph->ack_seq = 0;

    } else { /*原始数据包中ACK标记位没有置位的情况,初始连接SYN或者结束连接FIN等*/

    needs_ack = 1;

    /*这种情况应该是SYN或者FIN包,由于SYN和FIN包都占用1个字节的长度。因此ack_seq应该等于旧包的seq+1即可。这里之所以这样表示,可能是还存在其他情况的数据包。*/

    tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin

    + oldskb->len - oldskb->nh.iph->ihl*4

    - (oth->doff<<2));

    tcph->seq = 0;

    }

    /* RST标记位置1*/

    ((u_int8_t *)tcph)[13] = 0;

    tcph->rst = 1;

    tcph->ack = needs_ack;

    tcph->window = 0;

    tcph->urg_ptr = 0;

    /*重新计算TCP校验和*/

    tcph->check = 0;

    tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),

    nskb->nh.iph->saddr,

    nskb->nh.iph->daddr,

    csum_partial((char *)tcph,

    sizeof(struct tcphdr), 0));

    /* 修改IP包的TTL,并且设置禁止分片*/

    nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);

    /* Set DF, id = 0 */

    nskb->nh.iph->frag_off = htons(IP_DF);

    nskb->nh.iph->id = 0;

    /*重新计算IP数据包头部校验和*/

    nskb->nh.iph->check = 0;

    nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,

    nskb->nh.iph->ihl);

    /* "Never happens" */

    if (nskb->len > dst_mtu(nskb->dst))

    goto free_nskb;

    /*使nskb和oldskb的链接记录关联*/

    nf_ct_attach(nskb, oldskb);

    /*这里就是最终发送数据包的方式,具体方法就是让新数据包经过LOACLOUT的hook点,然后查路由,最后经由POSTROUTING点,将数据包发送出去。

    其实这里我还是有1个疑问:(1)为什么不可以直接查找路由,而必须先经过LOCALOUT点*/

    NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,

    dst_output);

    return;

    free_nskb:

    kfree_skb(nskb);

    }

    通过以上对send_reset函数的分析,应该明白了利用NF框架将构造数据包发送出去的方法。

    源码分析中提到的1个疑问,35楼给出了解释,这里引用过来:

    其实,这不是丢到了高层,而是和ip_queue_xmit()发送过程意义一样。

    对这包进行重新路由后,封装了头部,之后,放到了NF_IP_LOCAL_IN之前而已。

    其实,这里面只要修改了中途修改了ip地址,肯定是需要手动重新路由的。

    这就涉及到一些比较复杂的route cache的查找,如果没有就去查找route tables;之后,进行路由结构和neighbour结构的关联,就涉及到邻居子系统的相关操作;接着就涉及到arp cache的查找,如果没有,进行一些操作,arp的过程等等,才找到了相关的ip对应的mac信息。

    息。

    方法二,就是直接调用dev_queue_xmit函数,将构造完毕的数据包直接发送到网卡驱动。从NF框架来看,该函数的调用是在POSTROUTING点之后了,也可以理解为直接通过调用二层的发送函数,将三层构造的数据包发送出去。该函数实际上会调用skb->dev->hard_start_xmit,即对应网卡的驱动函数,将数据包直接发送的出去。

    很显然,这个工作在二层的函数,发送数据包(数据包在二层的时候准确叫法应该是帧,我们这里是在三层直接调用的,权且还称作数据包)的方式是不需要再查路由了。

    但是,二层发送的时候是需要根据目的MAC来进行的。在第一种方法构造的数据包中,仅仅交换了IP地址,而没有对MAC做任何修改。这样直接调用dev_queue_xmit是会产生问题的,并且该函数发送的内容应该是从二层头部开始,到数据包的结束。因此,如果三层构造的数据包,想调用该函数直接发送数据包的话,则需要修改数据包的源和目的MAC,并将skb->data指针指向MAC头部,以及skb->len的值也要加上头部的长度方法。以下是可参考的示例代码:

    unsigned char mac_temp[ETH_ALEN] = {0};

    struct ethhdr *mach = NULL;

    ……

    /*code…… 构造数据包的IP即上层协议及数据*/

    ……

    /*交换源和目的MAC*/

    mach = (struct ethhdr *)skb->mac.raw;

    memcpy(mac_temp, (unsigned char *)mach->h_dest, ETH_ALEN);

    memcpy(mach->h_dest, (unsigned char *)mach->h_source, ETH_ALEN);

    memcpy(mach->h_source, mac_temp, ETH_ALEN);

    /*修改skb->data指针,使其指向MAC头部,并且增加skb->len*/

    skb_push(skb , ETH_HLEN);

    /*直接调用该函数,将数据包从网卡上发送出去*/

    ret = dev_queue_xmit(skb);

    这里还要顺便说一下构造的数据包发送完毕之后,对于hook函数的返回值问题。    (1)第一种发送数据包的实现,对于send_reset函数的实现中,由于单独申请了nskb的内存,并构造的新的数据包。新数据包接着走NF的流程了。而对于原始的skb,就通过模块的返回值return NF_DROP做出了处理。    (2)第二种发送数据包的实现,若是基于已有数据包的基础上重新构造的数据包,那么实际上原始数据包的内容已经不复存在,而且调用完毕dev_queue_xmit已将同一块缓冲区,只是填充了新数据的数据包发送出去,因此,这里已经没有原始数据包的存在了,需要返回NF_STOLEN,告诉协议栈不用关心原始的包即可。否则,若是新数据包是单独申请的内存,那么对于原数据包还应该是返回NF_DROP. 三、总结         以上就是个人分享和总结和内核中构造的数据包发送出去的两种方式。实际中常用的就是构造完数据包之后,调用dev_queue_xmit函数发送报文,也测试过调用send_reset发送RST方式。但并未采用send_reset中通过调用NF_HOOK发送过其他数据包。如果诸位朋友有相关的实践经验,欢迎分享。         本文在分析send_reset代码的过程中,参考了百度中搜到的muddoghole的文章,因为只能从百度快照看到这篇文章,并且链接过长,这里就不列出连接,对于原文的作者表示感谢。         由于对内核中的一些地方理解不够深入,因此文章中肯定存在很多问题。欢迎各位朋友指正,多多交流。         本文原文链接:http://blog.chinaunix.net/u/33048/showart_2043789.html

    展开全文
  • 数据包发送与接收

    千次阅读 2021-12-09 18:37:52
    数据包发送与接收的过程

    封装和解封装

    应用层---HTTP超文本传输协议---TCP 80端口

            HTTPS=HTTP+SSL/TLS(比HTTP更安全)---TCP 443端口

            FTP文件传输协议---TCP 20/21端口

    TFTP简单文件传输协议---UDP 69端口

    telent远程登录协议---TCP 23端口

    SSH ---TCP 22端口

    DHCP 动态主机配置协议(自动获取IP地址---UDP67/68端口

    DNS 域名解析协议---UDP/TCP53端口

    传输层---端口号---TCP协议/UDP协议

    TCP和UDP的区别

    1. TCP是面向连接的协议,UDP是无连接的协议;
    2. TCP协议传输是可靠的,UDP协议传输“尽力而为”;
    3. TCP可以进行流控,UDP不行;
    4. TCP可以进行分段,UDP不行;
    5. TCP传输速度较慢,占用资源较大;UDP传输速度较快,占用资源小。

    TCP和UDP的场景应用:TCP更适合对传输可靠性要求较高,但是对速度要求较小的场景;UDP更适合对苏的要求较高,对可靠性要求较低的场景(即时通讯类)

    网络层---IP地址---IP协议

    数据链路层---MAC地址---以太网协议---以太网:早期局域网的解决方案,现在也用在广域网中。就是依靠MAC地址寻址的一二层网络。

    物理层

     

    什么是面向连接

    在正式传输数据之前,先通过预备好的协议(TCP协议),建立点到点的连接,之后再传输数据。

    TCP头部:

    URG(urgent紧急):紧急标志。紧急标志为"1"表明该位有效。

    ACK(acknowledgement 确认) :确认标志。表明确认编号栏有效。大多数情况下该标志位是置位的。TCP报头内的确认编号栏内包含的确认编号(w+1)为下一个预期的序列编号,同时提示远端系统已经成功接收所有数据。

    PSH(push传送):推标志。该标志置位时,接收端不将该数据进行队列处理,而是尽可能快地将数据转由应用处理。在处理Telnet或rlogin等交互模式的连接时,该标志总是置位的。

    RST:复位标志。用于复位相应的TCP连接。

    SYN(synchronous建立联机):同步标志。表明同步序列编号栏有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。在这里,可以把TCP序列编号看作是一个范围从0到4,294,967,295的32位计数器。通过TCP连接交换的数据中每一个字节都经过序列编号。在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。

    FIN(finish结束) :结束标志。

    Sequence number(顺序号码)
    Acknowledge number(确认号码)

    伪头部校验---32位源IP地址,32位目标IP地址,8位保留,8位协议,16位总长度---反码相加法

     

    UDP头部:

     

    TCP的三次握手---建立连接,不牵扯到任何数据,A发完后B即可同时回复同意和想要建立连接,所以为三次握手

     

    TCP的四次挥手---断开连接,存在数据传输,A先发完即可发送断开连接,B需要等自己全部发完才可发送断开连接,若A,B同时发完数据,则存在三次挥手的可能,但本质上还是四次挥手

     

    TCP传输可靠性的保障机制---确认,重传,排序,控流

    控流---滑动窗口流动机制:为了追求更快的传输效率,A会一直尝试增加win窗口的数量

     

    IP协议

     

    TCP和IP都是可变长头部

    TTL---生存时间---每当数据包经过一次路由器的转发,这个TTL值都将减1;当一个是数据包中的TTL值为0时,则路由器将不再对其进行转发,将直接丢弃。

    TCP---6

    UDP---17

    ICMP---1

    MTU---最大传输单元---1500字节(默认)---应用于网络层

    MSS---最大段长度---1460字节(减去IP协议和TCP协议)---在TCP三次握手过程中包含MSS,和SYN一起发送,取两者中小的那个。---应用于传输层

    <Huawei>---用户视图---<>

    用户视图只能执行查看操作,但是不能对设备进行配置

    <Huawei>display ip interface brief---查看接口IP配置情况摘要

    Physical---物理层面具备通信条件

    Protocol---协议层面具备通讯条件

    <Huawei>system-view---进入系统视图

    [Huawei]---系统视图---可以对设备进行全局类的配置

    [Huawei]sysname XX---修改设备名称

    [Huawei]interface GigabitEthernet 0/0/0------进入接口视图

    [Huawei-GigabitEthernet0/0/0]

    [Huawei-GigabitEthernet0/0/0]ip address 192.168.1.1 24---配置IP地址命令

    [Huawei-GigabitEthernet0/0/0]undo ip address 192.168.1.1 24---删除该操作---所有删除操作都是在原操作的基础上加上undo

    帮助系统

    Tab---自动补全命令

    ?---查看命令后面参数;可以查看该字母开头的所有命令

    展开全文
  • IP数据包格式 (1)版本 占4位,指IP协议的版本。通信双方使用的IP协议版本必须一致。广泛使用的IP协议版本号为4(即IPv4)。关于IPv6,还处于草案阶段 (2)首部长度 占4位,可表示的最大十进制数值是15。请注意,这...
  • 继上一篇介绍了数据包的接收过程后,本文将介绍在Linux系统中,数据包是如何一步一步从应用程序到网卡并最终发送出去的。 如果英文没有问题,强烈建议阅读后面参考里的文章,里面介绍的更详细。 本文只讨论以太网...
  • 转自:http://blog.chinaunix.net/u/33048/showart_2043789.html,作者:Godbach一、构造数据包简析这里并详细介绍如何在内核中构造数据包,下文如有需要会在适当的位置进行分析。这里简单的分析讲一下内核态基于...
  • Python发送数据包Scapy

    2021-08-12 17:33:01
    Python发送数据包 Scapy Scapy是Python的一个第三方库,兼容Python2和Python3,可以用来发送各个协议的数据包,就像Python语言中的一枚洲际导弹,想打哪打哪。 scapy是一个可以让用户发送、侦听和解析并伪装网络...
  • 作者:Godbach日期:2009/09/01一、构造数据包简析这里并详细介绍如何在内核中构造数据包,下文如有需要会在适当的位置进行分析。这里简单的分析讲一下内核态基于Netfilter框架构造数据包的方式。内核中可以用到的...
  • 它在协议结构上并没有占有一席之地,因此能通过协议栈注册协议的方式来申请网桥数据包的处理。相反,网桥接口的数据包和一般接口(如eth0)在格式上完全是一样的,不同之处是网桥在2层上就对它进行了转了,而...
  • 网络层次及数据包传输详解。
  • 计算机收发传统以太网1518...概述打打标记Tag,untag以及交换机的各种端口模式是网络工程技术人员调试交换机时接触最多的概念了。标记tag就是指VLAN的标签,数据包属于哪个VLAN的。交换机三种端口模式Access vla...
  • 【判断题】静态路由协议的优先级能手工指定。【单选题】以下哪种远程登录方式最安全?【多选题】如下图所示的网络,在RouterA设备里面存在如下配置,则下列说法正确的是? (多选)ip route-static 10.0.2.2 255.255.255...
  • 这是自动接收端口数据的代码packagetcpdemo_1;importjava.io.IOException;importjava.net.InetSocketAddress;importjava.nio.ByteBuffer;importjava.nio.channels.SelectionKey;impor...这是自动接收端口数据的代码...
  • luasocket从端口1900发送UDP数据(luasocket send UDP data from port 1900)我正试图从我的家庭自动...我正在跟踪此文件 ,将UDP数据从Controller的1900端口发送到Echo的端口50000。 现在我每次发送数据时Socket都会...
  • 数据包在网络中的传输过程详解

    千次阅读 2021-09-08 08:34:13
    我们当今使用电子设备都离开网络,通过网络我们可以聊天、玩游戏、看电影都操作。 网络的本质就是交换数据。 本文我们就来看下数据是如何在网络中传输的。 计算机网络模型 现在有两种计算机网络模型,分别为OSI七...
  • 端口扫描技术的原理是端口扫描目标主机的TCP / IP 服务端口发送探测数据包,并记录目标主机的响应。通过分析响应来判断服务端口是打开还是关闭,就可以得知端口提供的服务或信息。端口扫描也可以通过捕获本地主机...
  • wireshark分析数据包

    2021-01-13 10:57:31
    抓包常见的信息以及含义 TCP Previous segment not captured 说明乱序了,前一个包没有收到,收到后面的包了,这时会重...如果直到计时完成,发送方还是没有收到ACK回复,那么发送方推断之前发送的TCP片段丢失,因此
  • 1当所有已知路由信息都查数据包如何转发时 按 的信息进行转发当所有已知路由信息都查数据包如何转发时 按 的信息进行转发 静态路由 直连路由 默认路由 动态路由学习 2ICMP报网络可达是指 没有路由 协议...
  • HTTP数据包介绍

    2020-12-23 11:20:10
    1.HTTP数据包的请求结构 •一个http数据包请求由4个部分组成:请求...空行:最后一个请求头标之后是一个空行,发送回车符和退行,表示服务器以下不再有头标。 •4.请求数据:使用post传送数据,最常用的就是Content-T
  • 端口扫描器常见的端口扫描类型1. TCP 连接扫描2. TCP SYN 扫描(也称为半开放扫描或stealth扫描)3... UDP 扫描1、TCP连接扫描若客户端想要连接服务器80端口时,会先发送一个带有 SYN 标识和端口号的 TCP 数据包给服务...
  • access性质的端口只能属于一个vlan,且该端口不打tag,trunk可以属于多个vlan,可以接收和发送多个vlan的报文,一般用于交换机之间的连接;hybrid也可以属于多个vlan,可以接收和发送多个vlan的报文,可以用于交换机...
  • 数据包扩展

    2021-05-29 22:10:05
    在正常情况下访问为下图,浏览器对web server发送Request请求包,当web server收到之后,web server浏览器发送Response返回数据包 但是有正常就有正常,有时我们因为需要要设置代理(poxy).有代理时如下
  • Linux 之 常用端口

    2021-01-26 10:09:20
    一个计算机最多有65535个端口端口不能重复。 常用端口号:  IIS(HTTP):80  SQLServer:1433  Oracle:1521  MySQL:3306  FTP:21  SSH:22  Tomcat:8080 Telnet :...
  • 锐捷交换机 查看端口流量信息

    千次阅读 2020-12-30 13:37:23
    如果当前局域网的网段中有255个可用ip,使用交换机之后可以同时在网络的中存在的主机仍然是255个。即接在交换机上的所有设备的ip都在一个网络段中。 而使用路由器的话可以拓展到无限个主机,因为路由器可以作为网关...
  • 问题在linux系统如何抓取数据包进行分析解决方案linux上有两种比较好的抓包工具:ethereal和tcpdump对于ethereal,有图形界面和字符界面两种方式。到linux系统上执行rpm -qa | grep ethereal-gnome可查看是否安装了...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 98,436
精华内容 39,374
关键字:

向不存在的端口发送数据包