PHP,MySql登录系统

0.前置相关主题

  • php
  • mysql

1.首先建立配置数据库

首先建立一个webdata数据库,在该数据库中添加users表单,在表单中加入一些栏目。

1
2
3
4
5
6
7
8
9
+------------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(50) | NO | UNI | NULL | |
| password | varchar(255) | NO | | NULL | |
| created_at | datetime | YES | | CURRENT_TIMESTAMP | |
+------------+--------------+------+-----+-------------------+----------------+

那么数据库已经配置完成。

2.配置网页

看git仓库。

对于卷积的理解

对于卷积的理解:

首先,某一个时刻,一个信号进入系统之后,系统会输出一个信号,这个输出信号存在,但是,当输入信号消失后,输出信号依旧存在,但是其数值可能会改变,其输出信号可以通过系统的函数g(x)得到,那么,当输入的信号为连续的信号f(x),如何计算出这种情况下的输出信号呢?

那么就需要积分,更确切的说,就是卷积:

卷积也是积分的一种特殊形式,继续上面的问题,从0时刻输入一个连续的信号,那么第T时刻,该系统的输出为什么?

我们需要将第T时刻的输出信号进行积分,输出信号只有一个,但是从0到T,我们有连续的输入信号,在第t时刻输入的信号在第T时刻有输出信号为:f(t)×g(T-t),将这些输入信号积分得到:f(t)*g(t) = ∫T0f(t)×g(T-t)。

计算机网络入门(第一章)

来源:计算机网络自上向下方法

第一章 计算机网络与因特网
因特网:世界范围的计算机网络,接入这个网络的设备为主机host。
主机通过通信链路communication link和交换机packet switch连接到一起。
链路有不同的物理媒介,同轴电缆等。传输速度单位为bps。
当一台主机和另一台主机发送数据,发送端将数据分段,在段接上首部字节,术语为,形成的数据包为packet(又被称为分组),通过网络发送到目的主机,重新装配为初始数据。
分组交换机从一条通信链路接收到达的数据包,并从一条通信链路朝着最终的目的地转发该数据包,在当今的因特网中,分为两类:路由器router和链路层交换机link-layer switch。第四章研究路由器,第五章研究链路层交换机。
从发送端到接收端,一个数据包经历的一系列通信链路和分组交换及称为通过该网络的路径route/path。第一个交换机产生于20世纪70年代。对因特网通信量的分析,2005年,进入流量为250吉10^9比特每秒。
主机通过因特网服务提供商Internet Server Provider ISP接入因特网。
每个ISP是一个或者多个分组交换机和多段通信链路组成的网络,不同ISP为主机提供了不同的网络接入,包括拨号接入,局域网接入等。ISP也为内容提供者提供了因特网接入服务。将Web站点直接接入因特网。为了允许因特网用户之间的相互通信,低层的ISP通过高层ISP互相连接,例如低层ISP通过国家国际的高层ISP互联。无论高层或者低层ISP网络都是独立管理的,运行IP协议,遵从命名和地址习惯。
因特网的部件都要运行接受和发送的一系列协议protocol。
TCP Transmission Control Protocol 传输控制协议
IP Internet Protocol 网络协议
这两个是因特网中最重要的协议。IP协议定义了在路由器和主机的发送和接收的分组的格式。因特网的主要协议就是TCP/IP。
为了每个人能够就各个协议的作用达成共识,因特网标准Internet Standard由因特网工程任务组Internet Engineering Task Force IETF研发,IETF的标准文档被称为请求评论Request For Comment RFC。RFC最初为普通的请求评论,以解决因特网先驱的体系结构问题。定义了TCP,IP,HTTP用于Web,SMTP用于电子邮件的开放标准这样的协议。
公共因特网是一个特定的网络,具有全球性质。还有内部网络,类似于公司政府网络,这些主机不能与专用网络之外的主机交换信息,除非通过防火墙,否则会限制报文进入或者流出网络,这些网络被称为内联网intranet。它们与公共因特网由相同类型的主机,路由器,链路和协议。
除了以上的方法可以描述互联网,从另外一个角度而言,即为应用程序提供服务的基础设施角度。这些应用程序由电子邮件,Web冲浪,即时讯息,IP上的语音VoIP,广播,流式视频,分布式游戏,对等文件共享peer to peer等,这些程序称为分布式应用程序。因为他们涉及多台相互交换数据的主机。重要的是,因特网应用程序运行在主机上,尽管交换机促进了主机之间的数据交换,但是并不关心数据的源或宿主的应用程序。
当你开发了一个分布式因特网应用程序,运行在不同主机的软件需要相互发送数据。那么运行在一个主机的应用程序如何才能够指示因特网向另一个主机的软件发送数据。
与因特网相连的主机提供了一个应用程序编程接口Application Programming Interface API,规定了运行在一个主机上的软件请求因特网基础设施,向运行在另一个主机的特定目的地软件交付数据的方式。第二章会详细讨论因特网API。当然API与邮政服务类似,有不同种类的服务,因特网也为应用程序提供了多种服务。第三章描述因特网是如何提供那些服务的。
记住,因特网是一种基础设施,新的应用程序在这个基础上不断的发明与设置。

网络协议:
网络协议是一种交互过程,一方首先发起,开始与另一方进行通信,另一方会进行回应,根据回应来采取不同的动作。这要求两方都采用相同的协议。
以最常用的协议为例,当你向Web服务器发送请求,
1。主机向服务器发送连接请求的报文。
2。等待回答
3。Web服务器接收到连接请求的报文,返回连接响应的报文。
4。主机接收到连接响应的报文得知Web服务器状态正常后,
5。主机在一条GET报文中发送Web服务器上网页的名字,
6。Web服务器向计算机返回Web网页/文件

一个协议定义了在两个或者多个通话实体之间交换的报文格式和次序,以及在报文传输或接受其他事件所采取的动作。

一般而言,计算机网络广泛的使用了协议,不同的协议实现了不同的通信任务。一些协议简单直接,而一些协议复杂难懂,

与因特网相连接的设备是主机end system,主机又被进一步分为两类:
客户机client等同于桌面或者移动PC等
服务器server等同于存储或者发布Web页面,流视频以及转发电子邮件。
客户机程序是运行在一个主机的程序,它发出请求,从运行在另一个主机系统的服务器程序中接受服务。客户机-服务器模式是因特网上最流行的结构。同时P2P应用程序越来越广泛。

主机接入:
1。局域网LAN通常用于连接主机和路由器,以太网的运行速率是100Mbps以上。
2。无线接入由两种方式,无线局域网wireless LAN和广域无线接入网,用于蜂窝煤电话的相同无线基础设施进行发送,基站由电信提供商管理,为数万米半径的用户提供无线接入服务。

路由器从与它相连的一条通信链路中得到数据包,将数据包转发到另一条通信链路,那么路由器是如何确定它应当向哪条链路进行转发,不同的计算机网络采用不同的方法,因特网采用了以下的方法。
每个通过该网络传输的分组在首部包含了目的的地址,就像邮政地址一样,地址是一个层次结构,当分组到达网络中的一台路由器的时候,由每台路由器检查分组目的地址的一部分,并向相邻路由器转发该分组,特别的是,每个路由器都有一个转发表,用于将目的地址或目的地址的一部分映射到输出链路,当分组到达一台路由器时候,该路由器检查目的地址,并用这个目的地址来搜索转发表,找到合适的输出链路,然后路由器将该分组导向输出链路。

但是转发表是如何设置的在第四章讨论。因特网由特殊的选路协议,用于自动的设置转发表,例如选录协议可以决定每台路由器到每个目的地的最短路径,并使用这些最短路径来配置路由其中的转发表。

该过程和问路相似。

分组网络中的时延,丢包和吞吐量:

根据之前,因特网是为运行在主机上的分布式应用,提供服务的基础设施。理想情况下,希望因特网服务可以在任意两个主机上瞬间移动大量数据,而没有任何数据的丢失,然而,显示中很难做到。计算机网络必须限制主机之间的吞吐量,也就是,每秒能够传输的数据量。在主机中引入时延,丢包。

时延的描述:
数据包从一台主机出发,通过路由器传输,在另一台主机结束这个过程。当数据包从一个节点沿着路径到达后继节点,该分组经历了不同类型的时延。
nodal processing delay节点处理时延
检查分组首部和决定该数据包导向何处所需要的时间以及检查比特级差错所需要的时间等。
queuing delya 排队时延
当分组在链路上等待传输,如果队列为空,当前没有其他分组在传输,则分组时延为0。如果流量很大,有许多数据包在等待传输,排队时延就很大。
transmission delay传输时延
当所有已经到达的数据包被传输后,才会传输我们的数据包,L表示数据包的长度,R bps表示从A节点到B节点的链路传输速率。
例如,10M bps的以太网链路,R = 10 Mbps ,传输时延为L/R,这是将所有数据的比特传输向链路所需要的时间。
propagation delay 传播时延
一个比特被推向链路,该比特向B节点传播,从该链路的起点到B节点所需要的时间。与两个节点之间的距离有关。
这些时延总体累加为节点总时延dnodal
dnodal = dproc + dqueue + dtrans + dprop

排队延时和丢包:
这是最重要的一部分,也是复杂有趣的是排队时延dqueue,这种延时与其他延时不同,对于不同的数据包是不同的。如果有10个数据包同时到达空队列,传输的第一个数据包没有延时,最后一个将会有相对较大的排队延时,在表征排队延时,通常使用统计量来测量,例如,平均排队时延,排队时延的方差和排队时延超过某些特定值的概率。
那么什么时候排队时延较大?取决于流量到达该队列的速率,链路的传输速率和到达流量的性质,即流量是周期性到达或者突发式到达。
数据包到达队列的平均速度:a 单位:pkt/s 数据包每秒。
传输速率:R 单位: bps/s 比特从队列中推出的速率。
假设所有的数据包由L比特组成,则比特到达队列的平均速率是La bps。
最后假定队列的容量为无限大。
流量强度traffic intensity La/R,用于估计排队时延的影响程度。
如果La/R > 1,则比特到达队列的平均速率超过从该队列传输出去的速率,因此,队列将会一直增加,从而排队时延将会趋向于无穷大。所以设计系统时,流量强度不能够大于1。
如果数据包以突发性出现,而不是周期性出现,就可能会有很大的平均排队时延。
到达队列的过程通常是随机的,并不遵循任何模式。在这种真实的情况下,流量强度通常无法全面的表征时延的统计量。不过可以直观的理解排队时延的影响程度。特别,如果流量强度接近0,则几乎没有数据包到达,并且间隔时间很大,平均排队时延将接近0。
平均排队时延随着流量强度迅速增加。

丢包:
现实中,排队容量极大地依赖于路由器的设计与成本,但是一条链路前的队列只有有限的容量。所以,当流量强度接近1时,排队时延也不会趋向于无穷大,而是到达的数据包会发现一个满的队列。由于没有地方存储数据包,那么路由器将会丢弃这个数据包,该数据包将会丢失。

从主机的角度而言,上述现象看起来是一个数据包已经传输到网络核心,但是并不会出现在目的地,丢失数据的数量随着流量强度的增加而增加。引起,节点的性能不仅根据时延来度量,而且通过数据包丢失的概率来度量。

端到端的时延:
每个节点存在各个节点有不同的时延和平均排队时延的情况,需要对公式进行一般处理。

traceroute
运行在因特网上中的主机上,当用户指定一个目的主机名称,该程序会向该目的地发送多个特殊的分组。当这些分组向目的地传送时候,通过一系列的路由器,当路由器接受到这些分组之一时候,它会向源发送一个短报文,包括路由器的名字和地址。

具体而言,假定源与目的之间有N-1台路由器,则将向网络发送N个特殊的分组,每个分组地址指向最终的目的。这N个特殊分组标识为1到N,第n个分组的标识为n,第n台路由器接受到第n个特殊数据包,路由器会向其源发送一个报文,源会记录从发送第一个到接受对应返回报文所经受的时间,以及返回报文的路由器或目的主机的名字和地址。这种方式能够重建从源到目的地所采用的路由,以及所有中间路由器的往返时延。

实际上,对刚才的过程重复了3次,因此实际上,源发送了3 × N 个数据包。

当使用traceroute xxx时,发现星号,则是由于防火墙封掉了ICMP信息。或者在linux上使用traceroute,默认使用udp协议,除了第一跳,剩下的都是* * *。强制使用icmp就可以了,例如
traceroute -I xxx

计算机网络中的吞吐量
除了时延和丢包之外,计算机网络中另一个性能测度是端到端的吞吐量,从主机A到主机B通过计算机网络传输文件。

任何瞬间的瞬时吞吐量 instantaneous throughput 是主机B接受到该文件的速率 单位 bps。

如果,该文件有F比特,主机接收所有比特用了T秒,则文件传输的平均吞吐量 average throughput是 F/Tbps。

为了深入了解吞吐量,举例:吞吐量类似于最小割最大流算法,当然具体的算法早就忘记了。
但是具体情况下,我们需要了解分组层次和协议的问题。

协议层次和服务模型:
分层的体系系统:
通过分层可以以不同的方式来实现同一个功能,而其他部分不变,经常应用于大而且复杂并且不断更新的系统。
协议分层:
一个协议层以软件或者硬件来实现。HTTP和SMTP等应用层协议通常都是在主机中通过软件实现,运输层协议同样是这样。因为物理层和数据链路层负责处理跨特定链路的通信,它们通常在与给定链路相关的网络接口卡中实现。网络层通常是软件和硬件的混合体。注意,协议位于构成网络的主机或者其他组件中。

但是分层有一个潜在的缺点,某一层可能重复其较低层的功能。例如,许多协议栈都是基于链路和主机到主机这两种情况提供了差错恢复。
第二个潜在的缺点是,某层的功能可能需要仅在其他层才出现的信息,违反了层次分离的目标。

各层的所有协议被称为协议栈 protocol stack。因特网的协议栈由5个层次组成:
1.应用层:
网络应用程序及其应用层协议保存的地方,包含了许多的协议,例如:
HTTP:为Web文档提供了请求和传送
SMTP:提供了电子邮件报文的传输
FTP:提供了两个主机之间的文件传输
可以了解,将www.google.com这样的名字转换为32位比特网络地址,也是借助于域名系统DNS完成的,第二章中,创建和部署自己的新的应用层协议是非常容易的。

2.运输层:
提供了在应用程序主机之间传送应用层报文的服务,在因特网中,有两个运输层协议,即TCP和UDP,利用其中一个都可以传输应用层报文。
TCP向程序提供了面向连接的服务,这种服务包括了应用层报文向目的地的确保传递和流量控制。TCP将长报文划分为短报文,并且提供了拥塞控制机制,当网络拥塞时,源抑制其传输速率。
UDP协议向它的程序提供了无连接服务,这是一种不提供不必要服务的服务,不提供可靠性,没有流量控制,也没有拥塞控制,在书中,运输层数据包为报文段segment。

3.网络层:
网络层将数据报datagram的网络层数据包从一台主机移动到另一台主机。源主机中的因特网运输层协议TCP或者UDP向网络层递交运输层报文段和目的地地址。
网络层中包含著名的IP协议,定义了数据报中的各个字段以及主机或者路由器如何作用于这些字段。

4.链路层:
网络层通过一系列路由器在源和目的地之间发送分组,为了将数据包从一个节点移动到下一个节点,网络层必须依靠链路层的服务。在每个节点,网络层将数据下传给链路层,链路层沿着路径将数据传递给下一个节点。在下一个节点,链路层将数据上传到网络层。
链路层提供的服务取决于应用于该链路的特定链路层协议。链路层的数据包是帧frame。
将整个帧从一个网络元素移动到临近的网络元素。

5.物理层:
将某个帧的每个比特从一个节点移动到下一个节点。

同样存在一个7层的ISO OSI参考模型
1.应用层
2.表示层:
使通信程序能够解释交换数据的含义。提供了包含数据压缩,数据加密,数据描述。

3.会话层:
提供了数据交换的定界和同步功能,包括建立检查点和恢复方案。

4.运输层
5.网络层
6.链路层
7.物理层

报文,报文段,数据报和帧

应用层 报文
运输层 报文段
网络层 数据报
链路层 帧

攻击威胁下的网络

从因特网中发送接收数据中,会有恶意软件,能够影响我们的设备,一旦恶意软件感染了设备,就能够将信息发送到网络中,大多数的恶意软件是自我复制,一旦感染一台主机就会进入更多的主机。恶意软件就能够快速扩散。

病毒是一种需要某种形式的用户交互来感染用户设备的恶意软件。例如带有恶意执行代码的电子邮件。如果接受并打开这样的附件,就在不经意间运行了恶意软件。

蠕虫是一种无需任何明显用户交互就能够进入设备的恶意软件。

拒绝服务Denial of service DoS使合法的用户不能够使用网络,主机等。大多数Dos攻击属于下面的三种类型。

1.弱点攻击:
向目标主机上易受攻击的应用程序发送报文,可能使服务停止运行,甚至导致主机崩溃。

2.带宽洪泛:
向目的主机发送大量数据包,导致目标的接入链路变得拥堵,使合法的数据包无法到达服务器。

3.连接洪泛:
在目标主机中创建大量的半开或者全开TCP连接,目标主机因此停止合法的连接。

关于带宽洪泛攻击,单一攻击源可能无法产生足够大的流量来危害服务器,如果,从单一源发出所有流量,上游路由器可以检测出攻击并且在流量靠近服务器前就将其阻挡下来。

分布式DoS DDOS控制多个源让每个源对目标发送流量。难以检测和防御。
网络设计者需要通过不同方式应对DOS攻击,下面是三种DOS攻击的应对方法。

1.嗅探分组:

用户通过无线设备接入因特网,在无线传输设备附近放置被动接收机,该接收机就能够得到传输的每个分组的拷贝,这些分组中有各种敏感信息,记录每个流经的分组拷贝的被动接收机称为分组嗅探器,packet sniffer,就能够得到每个数据包的拷贝,包含各种敏感信息。

嗅探器也可以应用于有线环境中,因为分组嗅探器是被动的,它们不向信道中注入分组,从而难以检测它们的存在,所以当我们向无线信道发送分组时,某些坏家伙可能记录了我们分组的拷贝。那么防御嗅探的方法基本上都与密码学有关。

2.伪装成受信任的人:

生成具有任何源地址,分组内容和目的地址的分组,然后将这个人工制作的分组传输到因特网中,是非常容易的,因特网将该分组转发到目的地。

一个不可信的接受方接收了分组,用虚假的源地址伪装成真实的源地址,进而执行某些嵌入在该分组中的命令,例如修改转发表,将具有虚假源地址的分组注入到因特网中的能力被称为IP哄骗IP spoofing。这是用户能够冒充另一个用户的多种方式之一。

为了解决这个问题,需要使用端点鉴别 end-point authentication机制,来确保报文源于正确的地址。

3.修改或者删除报文

通过中间人攻击(man-in-middle attack),在这类攻击中,插入到两个通信实体之间的通信路径中。

A与B通信,在中间人通信中,坏家伙能够嗅探A和B之间的分组,并且能够危及A和B之间的数据的完整性。

结合上面三种情况,我们需要保证网络传输中的机密性,端点鉴别和完整性问题。

到这里第一章的内容就结束了。

Ubuntu上线程和进程教程

0.简介

一个进程可以具有多个异步执行的线程。异步执行使每个线程能够独立处理特定的工作或者服务,因此一个进程中运行的多个线程处理服务,构成了进程的完整的功能。
线程(thread):
线程通常作为调度程序所处理的最小处理单元。
进程(process):

为什么一个进程中需要多个线程,而不是只有一个主线程:

在一个进程中,存在实时输入,并且与每个输入相对应,产生一定的输出。
如果进程不是多线程,那么进程的处理则为同步,将接受输入,进行处理,产生输出。
局限性在于:该进程只有在完成的较早输入的处理后才会接受输入,在处理输入的时间长于预期的情况下,接受其它输入的操作将被搁置。

在socket服务器上,处理输入,处理,输出到socket客户端。
如果,任何输入时,服务器花费的时间超过了预期的时间,同时,另一个输入到达了socket服务器,那么服务器无法接受新的输入连接,卡在了处理旧的输入连接。
因此需要线程来实现异步执行。

进程与线程的差异:
1。进程不共享地址空间,而在统一进程下的线程共享地址空间。
2。进程是彼此独立执行的,进程之间的同步通过内核负责,另一方面,线程的同步必须由进程负责。
3。与进程的切换相比,线程的切换更快
4。两个进程的交互只能够通过标准的进程间通信来实现,而统一进程下执行的线程可以轻松地进行通信,因为共享大多数资源,例如内存,文本等。

用户线程和内核线程

线程可以存在于用户空间和内核空间中。

2 采用POSIX线程(pthread)库:

POSIX线程库是用于C / C ++的基于标准的线程API。它允许产生新的并发进程。可以更好的执行文件。

2.1 线程基础

线程操作包括创建,终止,同步(连接,阻塞),调度,数据管理和进程交互。

线程不维护已经创建线程的列表,也不知道创建该线程的线程。

进程的所有线程有共同的地址空间

一个进程的线程共享:
说明
数据
文件
信号和信号处理程序
当前工作目录
用户和组ID

每个线程都有唯一的
线程ID
寄存器集和堆栈指针
堆栈局部变量,返回地址
信号屏蔽
优先
返回值:errno

3.2线程创建和终止

需要头文件pthread.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *func_print(void *ptr);

int main()
{
pthread_t thread1,thread2;
const char *message1 = "thread 1";
const char *message2 = "thread 2";
int iret1,iret2;
iret1 = pthread_create(&thread1,NULL,func_print,(void*)message1);
if(iret1)
{
printf("Error_pthread create return code : %d\n",iret1);
exit(EXIT_FAILURE);
}

iret2 = pthread_create(&thread2,NULL,func_print,(void*)message2);

if(iret2)
{
printf("Error_pthread create return code : %d\n",iret2);
exit(EXIT_FAILURE);
}
printf("pthread_create() for thread 1 returns: %d\n",iret1);
printf("pthread_create() for thread 2 returns: %d\n",iret2);

pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
exit(EXIT_SUCCESS);
}


void *func_print(void *ptr)
{
char *message;
message = (char *)ptr;
printf("%s \n",message);
}

现在GNU编译器具有命令行选项”-pthread”,在早期的版本中使用”-lpthread”显式指定了pthread库。

1
gcc pthread.c -lpthread

该程序的输出结果不同,有以下的一些输出:

1
2
3
4
pthread_create() for thread 1 returns: 0
pthread_create() for thread 2 returns: 0
thread 1
thread 2
1
2
3
4
thread 1 
pthread_create() for thread 1 returns: 0
pthread_create() for thread 2 returns: 0
thread 2

等各种情况。

对上面的程序中引用的函数进行分析:
创建新的线程

1
2
3
4
5

int pthread_create(pthread_t * thread,
const pthread_attr_t * attr,
void * (*start_routine)(void *),
void *arg);

其中:
thread 返回线程ID。(在bits / pthreadtypes.h中定义的无符号long int)
attr 如果使用默认线程属性,则设置为NULL。(在bits / pthreadtypes.h中定义的struct pthread_attr_t结构的其他定义成员)属性包括:
分离状态(可联接吗?默认值:PTHREAD_CREATE_JOINABLE。其他选项:PTHREAD_CREATE_DETACHED)
调度策略(实时?PTHREAD_INHERIT_SCHED,PTHREAD_EXPLICIT_SCHED,SCHED_OTHER)
调度参数
Inheritsched属性(默认值:PTHREAD_EXPLICIT_SCHED从父线程继承:PTHREAD_INHERIT_SCHED)
作用域(内核线程:PTHREAD_SCOPE_SYSTEM用户线程:PTHREAD_SCOPE_PROCESS请选择一个或另一个,不要同时选择两者。)
防护尺寸
堆栈地址(请参见unistd.h和bits / posix_opt.h _POSIX_THREAD_ATTR_STACKADDR)
堆栈大小(在pthread.h中设置的默认最小PTHREAD_STACK_SIZE),
void start_routine) -指向要线程化的函数的指针。函数只有一个参数:指向void的指针。
* arg-指向函数参数的指针。要传递多个参数,请发送指向结构的指针。

等待另一个线程的停止

终止调用线程

3.3线程同步

3.4线程调度

3.5线程陷阱

3.6线程调试

3.7线程手册

Ubuntu上的C语言socket服务器教程

0 简介

socket服务器的运行方式:
1.打开socket
2.绑定到一个地址和端口
3.监听传入的连接
4.接受连接
5.读/发送数据

1.将socket绑定到端口

根据前面socket客户端可以知道建立socket,绑定将socket与地址和端口组合,需要一个类似于connect的sockaddr_in结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int socket_desc;
struct sockaddr_in server;

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket\n");
}

//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );

//Bind
if( bind(socket_desc,(struct sockaddr *)&amp;server , sizeof(server)) &lt; 0)
{
puts("bind failed\n");
}
puts("bind done\n");

绑定完成后,应该用socket连接了,将socket绑定到特定的ip和端口号,确认接受到,传入数据。
不能将两个socket绑定到同一个端口。

2 监听连接

将socket切换到listen模式

1
listen(socket_desc,3);

3 接受连接

3.1 接受连接不回复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc , char *argv[])
{
int socket_desc , new_socket , c;
struct sockaddr_in server , client;

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}

//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );

//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("bind failed\n");
}
puts("bind done\n");

//Listen
listen(socket_desc , 3);

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (new_socket<0)
{
puts("accept failed\n");
}

puts("Connection accepted");

return 0;
}

运行该程序,然后通过telnet程序连接本地的8888端口

1
telnet localhost 8888

获取连接的客户端的IP地址

1
2
3
char *client_ip = inet_ntoa(client.sin_addr);
int client_port = ntohs(client.sin_port);

3.2 回复客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int main(int argc , char *argv[])
{
int socket_desc , new_socket , c;
struct sockaddr_in server , client;
char *message;

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}

//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );

//Bind
if( bind(socket_desc,(struct sockaddr *)&amp;server , sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("bind done");

//Listen
listen(socket_desc , 3);

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (new_socket<0)
{
perror("accept failed");
return 1;
}

puts("Connection accepted");

//Reply to the client
message = "Hello Client , I have received your connection. But I have to go now, bye\n";
write(new_socket , message , strlen(message));

return 0;
}

3.3 保持服务器

在客户端连接到服务器之后立即关闭,为了保持服务器不间断运行,将accept置于循环之中,可以一直接受传入的连接。将服务器的程序修改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int main(int argc , char *argv[])
{
int socket_desc , new_socket , c;
struct sockaddr_in server , client;
char *message;

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );

//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("bind done");

//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while( new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c) )
{
puts("Connection accepted");

//Reply to the client
message = "Hello Client , I have received your connection. But I have to go now, bye\n";
write(new_socket , message , strlen(message));
if(new_socket < 0)
{
printf("accept failed");
}
}
return 0;
}

3.4 通过线程来处理多客户端连接

为了处理每个连接,需要单独的处理代码与服务器一起运行。通过线程来实现。
主服务器接受一个连接并且创建一个新的线程来处理该连接的通信,然后服务器返回接受更多的连接。

在Linux,可以使用pthread(posix线程)库完成线程,关于线程的教程在补充中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>

void *connect_server(void *);

int main(int argc , char *argv[])
{
int socket_desc , new_socket , c,*new_sock;
struct sockaddr_in server , client;
char *message;

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}

//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 5555 );

//Bind
if(bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("bind done");

//Listen
listen(socket_desc , 3);

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);

while(new_socket=accept(socket_desc,(struct sockaddr *)&client, (socklen_t*)&c))
{
puts("Connection accepted");

//Reply to the client
message = "Hello Client , I have received your connection.\n";
write(new_socket , message , strlen(message));

pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = new_socket;

if(pthread_create(&sniffer_thread,NULL,connect_server,(void*)new_sock) > 0)
{
printf("could not create thread");
return 1;
}
puts("handler assignment");
if(new_socket < 0)
{
printf("accept failed");
return 1;
}
}
return 0;
}

void *connect_server(void *socket_desc)
{
int sock = *(int *)socket_desc;
int read_size;
char *message,client_message[2000];
message = "Greetings!I am your connection handler\n";
write(sock,message,strlen(message));

message = "It is my duty to communicate with you\n";
write(sock,message,strlen(message));

while( (read_size = recv(sock,client_message,2000,0) ) > 0 )
{
if( strcmp(client_message,"exit") == 0)
{
fflush(stdout);
break;

}
write(sock,client_message,strlen(client_message));
}

if(read_size == 0)
{
puts("client disconnect");
fflush(stdout);
}
else if(read_size == -1)
{
puts("recv failed");
}

return 0;
}

codeblocks操作指南

1.快捷键

1
2
3
4
5
6
Ctrl+Shift+c //注释代码块
Ctrl+Shift+x //取消注释
Alt+方向键上下//将这一行进行上下移动
Tab //缩进当前或选中的块
Shift+Tab//减小缩进
Ctrl+Z//撤销

FAQ

codeBlocks编译undefined reference to错误
是没有把c文件编译进去的原因。

右键项目,选择属性,弹出窗体

然后选择build targets

在最下面有个build target files:中把c文件勾选。点击ok重新编译即可。

BitTorrent客户端教程

0 简介:

Bencode是BitTorrent在传输数据结构的编码方式。

常用在.torrent文档中,比纯二进制编码效率低,但是结构简单,而且不受到字节存储顺序的影响,对跨平台很重要。

磁链和种子的优缺点:
其实磁力链接本身是没什么用的,不管在任何软件的磁链下载中,都必须要先通过磁链得到种子文件,再使用种子文件进行常规下载。因为种子文件才有分片信息,文件大小,文件名等必要信息。所以可以看出,种子其实是必不可少的,那你可能会觉得奇怪,为什么还需要磁链呢?这是因为现在对BT的封锁太严重,传播种子并不是那么简单的事了,动不动就被和谐了,所以磁链的作用就是便于传输,因为磁链就是一个小小的文本,而种子确是一个文件呢~
总结一下他们的优缺点:
A.种子:稳定性高,信息多,不便于传播扩散
B.磁力链接:仍需要先获得种子,不稳定,可能在某时刻不能获取,但是很便于扩散。

有四种数据形态:

string 字符串
integer 整数
list 列表
dictionary字典表

1.Bencode编码格式

1.1 string字符串

1
2
3
5:hello
//<字符串长度>:<字符串>
//hello

1.2 integer整数

1
2
3
i1234e
//i<整数>e
//1234

1.3 list列表

1
2
l5:hello5:worldi1234ee
//l[data1][data2]...e

1.4 dictionary字典

1
2
d7:balancei1000e4:coin3:btce
//d[key1][value1][key2][value2]...e

key必须是string而且按照字母顺序排序

BitTorrent学习

资料来源:
维基百科:
https://zh.wikipedia.org/wiki/BitTorrent_(协议)

https://www.howtogeek.com/howto/31846/bittorrent-for-beginners-how-get-started-downloading-torrents/

BitTorrent协议时在对等网络中文件分享的网络协议程序。与point-to-point的协议程序不同。它为peer-to-peer,而且用户越多,下载同一文件的的人越多,下载速度越快。而且,下载之后,继续保持上传的状态.

https://www.howtogeek.com/wp-content/uploads/2010/10/Torrentcomp.gif

索引器:(indexers)

一个站点,汇集了种子列表和说明。

追踪器:(trackers)

一台服务器,协助指导同级,启动下载和维护统计信息,大多数索引器都有自己专用的追踪器,追踪器将少量的数据或数据包路由到下载器。收集下载者信息的服务器,并将此信息提供给其他下载者,是下载者连接起来,传输数据。

种子:
下载任务中,所有文件都被某个下载者完整的下载,下载者成为一个种子。

做种:
下载完成后,继续提供给他人下载的行为。

原理:

传统HTTP/FTP使用TCP/IP协议。
BitTorrent协议是TCP/IP协议上的一个P2P文件传输通信协议,处于应用层。正在不断扩展中。

协议中:
文件发布者会发布文件生成提供一个.torrent文件,种子文件。
包含Tracker信息和文件信息.
Tracker是追踪器服务器的地址和针对Tracker服务器的设置。
文件信息是根据对目标文件的计算生成,计算结果根据BitTorrent协议内的Bencode规则进行编码。
原理,将需要把提供下载的文件虚拟分成大小相等的块,块大小必须为2k的整数次方(由于是虚拟分块,硬盘上并不产生各个块文件),并把每个块的索引信息和Hash验证码写入种子文件中;所以,种子文件就是被下载文件的“索引”。

下载者要下载文件内容,就需要得到相应的种子文件,然后使用BT客户端进行下载。
下载时,BT客户端首先解析种子文件得到Tracker地址,然后连接Tracker服务器,Tracker服务器回应下载者的请求,提供下载者和其他下载者包括发布者的IP。

下载者连接其他下载者,根据种子文件,两者分别告知对方自己已有的块,交换对方没有的数据。此时不需要其他服务器才能与,分散了单个线路上的数据的流量,减轻了服务器的负担。

下载者每得到一个块,计算出下载块的Hash验证码与种子文件中的对比,如果一样则说明块正确,不一样则需要重新下载。解决了下载内容的准确性。

为了解决下完就跑的现象,在非官方的协议中存在一种慢慢开放下载内容的超级种子算法

在没有Tracker的情况下,发展出DHT网络技术。(Distributed Hash Table)分布式哈希表。是一种分布式存储方法。

在不需要服务器的情况下,每一个客户端负责一个小范围的路由,并且负责存储一小部分的数据,从而实现整个DHT网络的寻址和存储。使用该技术的BT下载软件,用户不需要连接Tracker就可以下载,因为软件会在DHT网络中寻找下载同一个文件的其他用户,并且与其通讯,开始下载任务。

有些软件可以通过自动DHT搜索种子资源,构成种子市场。(比特精灵)

DHT算法的名称位Kademlia(在eMule中也有使用,称为Kad网络)

BIT下载速度不够稳定,当中断种时则无法完整下载,当2009年tracker服务器无法展开解析工作。磁力连接就出现了。其中就有应用DHT网络技术。

取代Tracker服务器和BT种子的是DHT和PEX网络和Magnet Link。这是真正分布网络的。
DHT 保证了整个网络没有单个中心,即使一个节点下线,仍然可以通过其他节点来获取文件。

PEX Peer EXchange节点信息交换 虽然DHT解决了中心化的问题,但是没有Tracker实现高效寻址,就要PEX

Magnet links 告诉BT客户端寻找什么。

首先是客户端Becode的建立:

https://github.com/cwyang/bencode
见BT客户端的文章

The Pirate Bay海盗湾 世界上最大的电子信息分享网站,专门存储分类和搜索资源的网站,最大的BTTracker服务器

历史事件表:
该技术由2001年4月 布莱姆-科亨发布。七月正式使用。
中国大陆和西欧国家对BT没有法律上的约束,但是2009年,国家广播电影电视总局曾大范围打击和封锁中国的Tracker服务器

Ubuntu上C#使用

0 安装

1
2
sudo apt install mono-complete
sudo apt install monodevelop

好吧,我承认自己没有办法安装monodevelop出现了各种问题,但是,有其他方法,IDE我重新选择了Rider,破解简单,而且下载方便。

1 快速入门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
vim hello.cs

//hello.cs
using System;

//namespace declaration
//namespace is a collection of classes
namespace HelloWorldApplication {

//class declaration
//class generally contain multiple methods,data
class HelloWorld {

//Main method is the entry point for all c# programs
static void Main(string[] args) {
/* my first program in C# */
Console.WriteLine("Hello World");
Console.ReadKey();
}
}
}

//编译
mcs hello.cs

//执行
mono hello.exe