一、传输层socket(四层socket,普通socket)

可参考本人以下博客:

Windows Socket编程之UDP实现大文件的传输:http://blog.csdn.net/luchengtao11/article/details/71016222

Windows Socket编程之TCP实现大文件的传输:http://blog.csdn.net/luchengtao11/article/details/71012580

(1)创建

  1.  
    socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//TCP
  2.  
    //或者
  3.  
    socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//UDP

AF_INEF表示TCP/IP族

第三个参数可以为0,由操作系统自行选择

(2)发送

  sendto(sd,buffer,BUFSIZ,0,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));//UDP
 
  send(sd, buffer, BUFSIZ, 0);  //TCP
 

(3)接收

recvfrom(sd,buffer,BUFSIZ,0,(SOCKADDR*)&addrClient,sizeof(SOCKADDR));//UDP
 
recv(sd, buffer, BUFSIZ, 0);//TCP
 

sd为socket标识符,buffer为接受/发送缓冲区,BUFSIZ为接受/发送缓冲区。后两个参数为发送或接受的对方地址,可以为NULL

二、网络层socket(三层socket)

可以参考本人一下博客或代码:

Linux下的raw Socket(原始套接字)编程:http://blog.csdn.net/luchengtao11/article/details/73878760

网络层多线程收发:https://github.com/Wuchenwcf/MyCode/blob/master/C%2B%2B/Linux/computer%20network/raw_socket_%E7%BD%91%E7%BB%9C%E5%B1%82%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%94%B6%E5%8F%91.cpp

(1)创建

socket(AF_INET, SOCK_RAW, IPPROTO_UDP );//第三个参数可以是UDP,TCP或者ICMP
 

(2)接收

recvfrom(sd, buffer, sizeof(buffer), 0,(struct sockaddr *)&client_addr, &addrlen));// 
 

后两个参数可以为null

接受的报文是从IP数据报的第一个字节开始的。

当内核有一个需要传递到原始套接字的IP数据报时,它将检查所有进程上的原始套接字,以寻找所有匹配的套接字。每个匹配懂得套接字将被递送以该iP数据报的一个副本。(事实证明,如果进程过多,匹配的套接字过多,内核会忙于数据报的软过滤和分发,而实际的套接字却空闲,导致性能下降)
内核对每个原始套接字均执行如下3个测试,只有这三个测试为真,内核才把接收到的数据报递送到这个套接字。

【1】如果创建这个套接字时制订了非0的协议参数(socket的第三个参数),那么接受到的数据报的协议字段必须匹配该值,否则数据报不递送到这个套接字

【2】如果这个原始套接字已由bind调用绑定了某个本地IP地址,那么接受到的数据报的目的IP地址必须匹配这个绑定的地址,否则该数据报不递送到这个套接字。

【3】如果这个原始套接字已由connect调用指定了某个外地IP地址,那么接受到的数据报的源IP地址必须匹配这个已连接地址,否则该数据报不递送到这个套接字。

注意,如果一个原始套接字以0值协议参数创建的,而且没有bind和connect,那么该套接字将接收可由内核传递到原始套接字的每个原始数据报的一个副本。

(3)发送

  1.  
    /*
  2.  
    如果IP_HDRINCL未开启,由进程让内核发送的数据是从IP首部之后的第一个字节开始的,内核会自动构造合适的IP
  3.  
    如果IP_HDRINGL开启,进程需要自行构造IP包
  4.  
    */
  5.  
    /*
  6.  
    if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(int)))
  7.  
    {
  8.  
    perror("setsockopt() error");
  9.  
    exit(-1);
  10.  
    }
  11.  
    */
  12.  
    sendto(sd, buffer, request_length, 0, (sockaddr *)&client_addr, addrlen);

三、数据链路层scoket(二层socket)

代码可以参考:

raw_socket_数据链路层收发实例:https://github.com/Wuchenwcf/MyCode/blob/master/C%2B%2B/Linux/computer%20network/raw_socket_%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82%E6%94%B6%E5%8F%91%E5%AE%9E%E4%BE%8B.cpp

(1)创建

sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));//第三个参数可以为ETH_P_ALL ETH_P_IP ETH_P_ARP等
 

(2)接受

  1.  
    struct sockaddr_ll client;
  2.  
    socklen_t addr_length = sizeof(sockaddr_ll);
  3.  
    recvfrom(sock, buffer, 2048, 0, (sockaddr *)&client, &addr_length);//此时的地址是数据链路层的地址

接受的报文是从以太网的帧开始的

(3)发送

sendto(sock, sendbuffer, n, 0, (struct sockaddr *) &client, sizeof(client));
 

四、小结

引用:http://blog.csdn.net/firefoxbug/article/details/7561159

网卡对该数据帧进行硬过滤(根据网卡的模式不同会有不同的动作,如果设置了promisc混杂模式的话,则不做任何过滤直接交给下一层输入例程,否则非本机mac或者广播mac会被直接丢弃).按照上面的例子,如果成功的话,会进入ip输入例程.但是在进入ip输入例程之前,系统会检查系统中是否有通过socket(AF_PACKET, SOCK_RAW, ..)创建的套接字.如果有的话并且协议相符,在这个例子中就是需要ETH_P_IP或者ETH_P_ALL类型.系统就给每个这样的socket接收缓冲区发送一个数据帧拷贝.然后进入下一步.

其次,进入了ip输入例程(ip层会对该数据包进行软过滤,就是检查校验或者丢弃非本机ip或者广播ip的数据包等,具体要参考源代码),例子中就是如果成功的话会进入udp输入例程.但是在交给udp输入例程之前,系统会检查系统中是否有通过socket(AF_INET, SOCK_RAW, ..)创建的套接字.如果有的话并且协议相符,在这个例子中就是需要IPPROTO_UDP类型.系统就给每个这样的socket接收缓冲区发送一个数据帧拷贝.然后进入下一步。

最后,进入udp输入例程 ...

ps:如果校验和出错的话,内核会直接丢弃该数据包的.而不会拷贝给sock_raw的套接字,因为校验和都出错了,数据肯定有问题的包括所有信息都没有意义了.

raw_socket(原始套接字)以及普通socket使用终极总结的更多相关文章

  1. Raw Socket(原始套接字)实现Sniffer(嗅探)

    参考资料: https://www.xuebuyuan.com/3190946.html https://blog.csdn.net/zxygww/article/details/52093308 i ...

  2. linux原始套接字(2)-icmp请求与接收

    一.概述                                                    上一篇arp请求使用的是链路层的原始套接字.icmp封装在ip数据报里面,所以icmp请 ...

  3. Go中原始套接字的深度实践

    1. 介绍 2. 传输层socket 2.1 ICMP 2.2 TCP 2.3 传输层协议 3. 网络层socket 3.1 使用Go库 3.2 系统调用 3.3 网络层协议 4. 总结 4.1 参考 ...

  4. 原始套接字-自定义IP首部和TCP首部

    /* ===================================================================================== * * Filenam ...

  5. 原始套接字--简易ping程序

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> ...

  6. Linux基础(11)原始套接字

    一边接收函数返回一边判断返回值时一定要把接收的优先级加()提高再去判断 例 if((sockfd = socket()) < 0) 问题: 如何实现SYN扫描器扫描端口 , 比如AB两个设备要进 ...

  7. Linux Socket 原始套接字编程

    对于linux网络编程来说,可以简单的分为标准套接字编程和原始套接字编程,标准套接字主要就是应用层数据的传输,原始套接字则是可以获得不止是应用层的其他层不同协议的数据.与标准套接字相区别的主要是要开发 ...

  8. Linux系统编程(37)—— socket编程之原始套接字

    原始套接字的特点 原始套接字(SOCK_RAW)可以用来自行组装IP数据包,然后将数据包发送到其他终端.也就是说原始套接字是基于IP数据包的编程(SOCK_PACKET是基于数据链路层的编程).另外, ...

  9. 《Python黑帽子:黑客与渗透测试编程之道》 网络:原始套接字和流量嗅探

    Windows和Linux上的包嗅探: #!/usr/bin/python import socket import os #监听的主机 host = "10.10.10.160" ...

随机推荐

  1. == 和 equal 区别

    在初学 Java 时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = new String(" ...

  2. LeetCode(47):全排列 II

    Medium! 题目描述: 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [1,1,2] 输出: [ [1,1,2], [1,2,1], [2,1,1] ] 解题思路: 这道 ...

  3. 步步为营-47-分页显示的SQL语句

    说明:分页显示在实际业务中经常需要用到,其SQL语句分两种 1:分页显示SQL语句 --方法一:跳过多少行,选中多少行 --每页n条,选择第m页--n= m= --)*n 主键 from 表); se ...

  4. Redis 5.0 集群搭建

    Redis 5.0 集群搭建 单机版的 Redis 搭建 https://www.jianshu.com/p/b68e68bbd725 /usr/local/目录 mkdir redis-cluste ...

  5. Struts2的动态Action和全局跳转视图以及配置各项默认值

    1:Struts2的默认访问后缀是.action(特别需要注意的是改了配置文件web.xml或者struts.xml需要重启服务器) 2:Struts2中常用的常量介绍:<!-- 一:全局配置 ...

  6. PHP 三元运算 ??与?:

    //$c = $a ?? $b; 等效 $c = isset($a) ? $a : $b; //$c = $a ?: $b; 等效 $c = $a ? $a : $b; $a = 'a'; $b = ...

  7. eclipse无法添加tomcat

    问题如图所示 就是选择对应的版本无法选择硬盘里面的tomcat文件 关闭Eclipse 删除WorkSpace目录下/.metadata/.plugins/org.eclipse.core.runti ...

  8. Arbitrage HDU1217

    汇率转换问题: 怎么样才能套利 可以用Floyd算法: #include<bits/stdc++.h> using namespace std; ][]; int main() { int ...

  9. vue+axios实现移动端图片上传

    在利用vue做一些H5页面时,或多或少会遇到有图片上传的操作,主要是运用html5里面的input[type=file]来实现,传递到后端的数据是以二进制的格式传递,所以上传图片的请求与普通的请求稍微 ...

  10. mysql中的用法 count group by having

    1 语法: group by 字段 having 条件判断; group by的用法我已经在上一篇经验中介绍了 2 还是已员工绩效表为例   3 我们如果就是查询每个部门成绩大于89的员工数,可以这样 ...