
int reqsk_queue_alloc(struct request_sock_queue *queue,
unsigned int nr_table_entries)
{
size_t lopt_size = sizeof(struct listen_sock);
struct listen_sock *lopt;
//计算半连接队列的长度
nr_table_entries = min_t(u32, nr_table_entries, sysctl_max_syn_backlog);
nr_table_entries = max_t(u32, nr_table_entries, 8);
..
//为半连接队列申请内存
lopt_size += nr_table_entries * sizeof(struct request_sock );
if (lopt_size > PAGE_SIZE)
/ 如果申请内存大于1页,则申请虚拟地址连续的空间 /
lopt = __vmalloc(lopt_size,GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,PAGE_KERNEL);
else
/ 申请内存在1页内,则申请物理地址连续的空间 */
lopt = kzalloc(lopt_size, GFP_KERNEL);
//全连接队列头初始化
queue->rskq_accept_head = NULL;
// 半连接队列的最大长度
lopt->nr_table_entries = nr_table_entries;
...
//半连接队列设置
queue->listen_opt = lopt;
return 0;
}
int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
...
//设置 socket 状态为 TCP_SYN_SENT
tcp_set_state(sk, TCP_SYN_SENT);
...
//函数用来根据 sk 中的信息,构建一个完成的 syn 报文,并将它发送出去。
err = tcp_connect(sk);
...
}
int tcp_connect(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *buff;
tcp_connect_init(sk);
//申请 skb 并构造为一个 SYN 包
buff = alloc_skb_fclone(MAX_TCP_HEADER + 15, sk->sk_allocation);
...
//添加到发送队列 sk_write_queue 上
__skb_queue_tail(&sk->sk_write_queue, buff);
...
//发送syn报文
tcp_transmit_skb(sk, buff, 1, GFP_KERNEL);
...
/* Timer for repeating the SYN until an answer. */
//启动重传定时器
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
inet_csk(sk)->icsk_rto, TCP_RTO_MAX);
return 0;
}int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
{
...
//服务器收到第一步握手 SYN 或者第三步 ACK 都会走到这里
if (sk->sk_state == TCP_LISTEN) {
//从半连接表syn_table中取出节点
struct sock *nsk = tcp_v4_hnd_req(sk, skb);
...
}
}static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
{
// 从半连接队里中查询
struct request_sock *req = inet_csk_search_req(sk, &prev, th->source, iph->saddr, iph->daddr);
return sk;
}
struct request_sock *inet_csk_search_req(const struct sock *sk,
struct request_sock ***prevp,
const __be16 rport, const __be32 raddr,
const __be32 laddr)
{
for (prev = &lopt->syn_table[inet_synq_hash(raddr, rport, lopt->hash_rnd,
lopt->nr_table_entries)];
(req = *prev) != NULL;
prev = &req->dl_next) {
...
}
}
return req;
}int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th, unsigned len)
{
...
case TCP_LISTEN:
...
//判断是否为 SYN 包
if(th->syn) {
//调用 tcp_v4_conn_request
if (icsk->icsk_af_ops->conn_request(sk, skb) < 0)
return 1;
...
}
goto discard;
case TCP_SYN_SENT:
...
return 0;
}int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
...
//查看半连接队列是否已满
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
#ifdef CONFIG_SYN_COOKIES
if (sysctl_tcp_syncookies) {
want_cookie = 1;
} else
#endif
goto drop;
}
//在全连接队列满的情况下,如果有 young_ack,那么直接丢
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
goto drop;
//分配 request_sock 内核对象,该request_sock->sk 此时还为空
req = reqsk_alloc(&tcp_request_sock_ops);
if (!req)
goto drop;
...
tcp_rsk(req)->snt_isn = isn;
// 发送 syn+ack 包
if (tcp_v4_send_synack(sk, req, dst))
goto drop_and_free;
if (want_cookie) {
reqsk_free(req);
} else {
//添加到半连接队列,并开启计时器,
inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
}
return 0;
}
int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th, unsigned len)
{
...
switch (sk->sk_state) {
case TCP_CLOSE:
goto discard;
case TCP_LISTEN:
...
case TCP_SYN_SENT:
//处理 synack 包,返回值大于0表示需给对方发送RST段,该TCP段的释放由tcp_rcv_state_process调用者处理
queued = tcp_rcv_synsent_state_process(sk, skb, th, len);
if (queued >= 0)
return queued;
/* Do step6 onward by hand. */
//在处理完接收的段后,还需要处理紧急数据,然后释放该段,最后检测是否有数据需要发送。
tcp_urg(sk, skb, th);
__kfree_skb(skb);
tcp_data_snd_check(sk, tp);
return 0;
}
...
return 0;
}static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th, unsigned len)
{
...
if (th->ack) {
...
//若收到ack+rst段,则调用tcp_reset设置ECONNREFUSED错误码,同时通知等待该套接口的进程,然后关闭套接口
if (th->rst) {
tcp_reset(sk);
goto discard;
}
//在SYS_SENT状态下接收的段必须存在SYN标志,否则说明接收到的段无效,然后跳到discard_and_undo丢弃该段
if (!th->syn)
goto discard_and_undo;
TCP_ECN_rcv_synack(tp, th);
// 初始化与窗口有关的成员变量
tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
tcp_ack(sk, skb, FLAG_SLOWPATH);// 删除发送队列和重传定时器
/* Ok.. it's good. Set up sequence numbers and
• move to established.
*/
tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
...
//设置已完成连接状态
tcp_set_state(sk, TCP_ESTABLISHED);
...
//初始化拥塞控制
tcp_init_congestion_control(sk);
...
//若启用了连接保活,则启用连接保活定时器
if (sock_flag(sk, SOCK_KEEPOPEN))
inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));
if (!tp->rx_opt.snd_wscale)
__tcp_fast_path_on(tp, tp->snd_wnd);
else
tp->pred_flags = 0;
//若不处于SOCK_DEAD,则唤醒等待该套接口的进程,同时向套接口的异步等待队列上的进程发送信号,通知他们该套接口可以输出数据了
if (!sock_flag(sk, SOCK_DEAD)) {
/* 指向sock_def_wakeup,会唤醒调用connect()的进程,完成连接的建立 /
sk->sk_state_change(sk);
/ 如果使用了异步通知,则发送SIGIO通知进程可写 */
sk_wake_async(sk, 0, POLL_OUT);
}
...
discard:
__kfree_skb(skb);
return 0;
} else {
// 发送ack段,同时更新窗口。
tcp_send_ack(sk);
}
return -1;
}
...
}void tcp_send_ack(struct sock sk)
{
/ If we have been reset, we may not send again. */
//发送ack时,tcp必须不在TCP_CLOSE状态
if (sk->sk_state != TCP_CLOSE) {
...
//为ack分配一个SKB,若分配失败则在启动延时确认定时器后返回
buff = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC);
...
/* Send it off, this clears delayed acks for us. */
//设置序号和发送时间,调用tcp_transmit_skb将ack段发送出去
TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp);
TCP_SKB_CB(buff)->when = tcp_time_stamp;
tcp_transmit_skb(sk, buff, 0, GFP_ATOMIC);
}
}int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
{
...
//服务器收到第一步握手 SYN 或者第三步 ACK 都会走到这里
if (sk->sk_state == TCP_LISTEN) {
//从半连接表syn_table中取出连接请求块request_sock,同时生成一个新的sock结构
struct sock *nsk = tcp_v4_hnd_req(sk, skb);
if (!nsk)
goto discard;
// 新生成的sock和监听的不一样
if (nsk != sk) {
//设置状态 TCP_ESTABLISHED并唤醒阻塞在accept上的进程
if (tcp_child_process(sk, nsk, skb)) {
rsk = nsk;
goto reset;
}
return 0;
}
}
...
}
static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
{
...
// 从半连接hash表中获取连接请求块request_sock
struct request_sock *req = inet_csk_search_req(sk, &prev, th->source,
iph->saddr, iph->daddr);
if (req)
return tcp_check_req(sk, skb, req, prev);
...
}
inet_csk_search_reqstruct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
struct request_sock *req,
struct request_sock **prev)
{
...
//创建子 socket ,调用 tcp_v4_syn_recv_sock
child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb,
req, NULL); //tcp_v4_syn_recv_sock
//清理半连接队列
inet_csk_reqsk_queue_unlink(sk, req, prev);
inet_csk_reqsk_queue_removed(sk, req);
//把request_sock和生成的sock进行关联,并把request_sock添加到全连接队列
inet_csk_reqsk_queue_add(sk, req, child);
return child;
...
}struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct dst_entry *dst)
{
...
//判断接收队列是不是满了,若满,丢弃
if (sk_acceptq_is_full(sk))
goto exit_overflow;
...
//创建 sock && 初始化
newsk = tcp_create_openreq_child(sk, req, skb);
...
// 把 newsk 加入到 已完成链接的ehash hash表中
__inet_hash(&tcp_hashinfo, newsk, 0);
__inet_inherit_port(&tcp_hashinfo, sk, newsk);
...
}int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, struct tcphdr *th, unsigned len)
{
...
if (th->ack) {
...
switch(sk->sk_state) {
case TCP_SYN_RECV:
//设置状态 TCP_ESTABLISHED
tcp_set_state(sk, TCP_ESTABLISHED);
...
}
struct sock *inet_csk_accept(struct sock *sk, int flags, int *err)
{
...
if (sk->sk_state != TCP_LISTEN) /* socket必须处于监听状态 *
goto out_err;
/* Find already established connection /
// 发现没有ESTABLISHED状态的连接请求块
if (reqsk_queue_empty(&icsk->icsk_accept_queue)) {
/ 等待超时时间,如果是非阻塞则为0 */
long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
/* If this is a non blocking socket don't sleep /
error = -EAGAIN;
if (!timeo) / 如果是非阻塞的,则直接退出 /
goto out_err;
/ 阻塞等待,直到有全连接。如果用户有设置等待超时时间,超时后会退出 /
error = inet_csk_wait_for_connect(sk, timeo);
if (error)
goto out_err;
}
/ 获取新连接的sock,释放连接控制块 */
newsk = reqsk_queue_get_child(&icsk->icsk_accept_queue, sk);
BUG_TRAP(newsk->sk_state != TCP_SYN_RECV);
out:
release_sock(sk);
return newsk;
out_err:
newsk = NULL;
*err = error;
goto out;
}static inline struct sock *reqsk_queue_get_child(struct request_sock_queue *queue,
struct sock parent)
{
/ 从全连接队列中,取出第一个ESTABLISHED状态的连接请求块 */
struct request_sock *req = reqsk_queue_remove(queue);
struct sock child = req->sk; / 一个已建立的连接 */
BUG_TRAP(child != NULL);
/* 当前backlog队列的全连接数减一 */
sk_acceptq_removed(parent);
__reqsk_free(req);
return child;
}
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识
是否可以在不实际下载文件的情况下检查文件是否存在?我有这么大的(~40mb)文件,例如:http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm这与ruby不严格相关,但如果发件人可以设置内容长度就好了。RestClient.get"http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm",headers:{"Content-Length"=>100} 最佳答案
我在这方面尝试了很多URL,在我遇到这个特定的之前,它们似乎都很好:require'rubygems'require'nokogiri'require'open-uri'doc=Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html"))putsdoc这是结果:/Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:353:in`open_http':404NotFound(OpenURI::HT
在Ruby(1.8.X)中为什么Object既继承了内核又包含了内核?仅仅继承还不够吗?irb(main):006:0>Object.ancestors=>[Object,Kernel]irb(main):005:0>Object.included_modules=>[Kernel]irb(main):011:0>Object.superclass=>nil请注意,在Ruby1.9中情况类似(但更简洁):irb(main):001:0>Object.ancestors=>[Object,Kernel,BasicObject]irb(main):002:0>Object.included
深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG
(本文是网络的宏观的概念铺垫)目录计算机网络背景网络发展认识"协议"网络协议初识协议分层OSI七层模型TCP/IP五层(或四层)模型报头以太网碰撞路由器IP地址和MAC地址IP地址与MAC地址总结IP地址MAC地址计算机网络背景网络发展 是最开始先有的计算机,计算机后来因为多项技术的水平升高,逐渐的计算机变的小型化、高效化。后来因为计算机其本身的计算能力比较的快速:独立模式:计算机之间相互独立。 如:有三个人,每个人做的不同的事物,但是是需要协作的完成。 而这三个人所做的事是需要进行协作的,然而刚开始因为每一台计算机之间都是互相独立的。所以前面的人处理完了就需要将数据
安全产品安全网关类防火墙Firewall防火墙防火墙主要用于边界安全防护的权限控制和安全域的划分。防火墙•信息安全的防护系统,依照特定的规则,允许或是限制传输的数据通过。防火墙是一个由软件和硬件设备组合而成,在内外网之间、专网与公网之间的界面上构成的保护屏障。下一代防火墙•下一代防火墙,NextGenerationFirewall,简称NGFirewall,是一款可以全面应对应用层威胁的高性能防火墙,提供网络层应用层一体化安全防护。生产厂家•联想网御、CheckPoint、深信服、网康、天融信、华为、H3C等防火墙部署部署于内、外网编辑额,用于权限访问控制和安全域划分。UTM统一威胁管理(Un
Linux操作系统——网络配置与SSH远程安装完VMware与系统后,需要进行网络配置。第一个目标为进行SSH连接,可以从本机到VMware进行文件传送,首先需要进行网络配置。1.下载远程软件首先需要先下载安装一款远程软件:FinalShell或者xhell7FinalShellxhell7FinalShell下载:Windows下载http://www.hostbuf.com/downloads/finalshell_install.exemacOS下载http://www.hostbuf.com/downloads/finalshell_install.pkg2.配置CentOS网络安装好
文章目录一基础定义二创建逻辑卷2-1准备物理设备2-2创建物理卷2-3创建卷组2-4创建逻辑卷2-5创建文件系统并挂载文件三扩展卷组和缩减卷组3-1准备物理设备3-2创建物理卷3-3扩展卷组3-4查看卷组的详细信息以验证3-5缩减卷组四扩展逻辑卷4-1检查卷组是否有可用的空间4-2扩展逻辑卷4-3扩展文件系统五删除逻辑卷5-1备份数据5-2卸载文件系统5-3删除逻辑卷5-4删除卷组5-5删除物理卷六LVM逻辑卷缩容6-1缩容注意事项6-2标准缩容步骤一基础定义LVM,LogicalVolumeManger,逻辑卷管理,Linux磁盘分区管理的一种机制,建立在硬盘和分区上的一个逻辑层,提高磁盘分