Http协议、线程、线程池

Socket模拟服务端运行代码:

1:启动服务端监听的服务,并接受客户端的连接

   1.1 创建Socket

   Socket listenSocket=new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);

   1.2绑定端口和ip地址

   IPAddress ip = IPAddress.Parse(this.txtIp.Text);

IPEndPoint endPoint=newIPEndPoint(ip,

                         int.Parse(this.txtPort.Text));

   listenSocket.Bind(endPoint);

1.3开始监听

2:启动开始接受客户端连接的线程,开始接受客户端的连接工作。

   Accept会阻塞当前主线程(用到多线程),直到有客户端连接上来,并返回  具体通信的Socket。我们必须让当前的监听的Socket不断地执行Accept方  法(放到while循环 中)才能够拿到通信的Socket。

   proxSocket 就是负责跟具体一个客户端的通信,可以通过proxSocket 拿   到远程客户端    的ip和端口。

   Socket proxSocket = listenSocket.Accept();

3: 服务器端不停的监听客户端的发送来的消息。

   proxSocket.Receive();

   Receive:能阻塞执行此代码的线程。创建一个不断接受客户端连接发送来的消息的线程.   而且Receive方法跟流中Read非常相似,每次读取操作都是从上次读取的节点处继续往  下读取数据。

Int realLen = proxSocket.Receive(buffer);//返回值是一个具体收到的字节数.可以通过      realLen的长度来半段客户端是否有信息返回,如果realLen的值为0, 代表客户端 退出   的一个信号关闭Socket ,关闭当前的Socket接受数据的线程在客户端集合中移除掉当的    代理对象。

proxSocket.Shutdown(SocketShutdown.Both);

proxSocket.Close();//关闭当前的Socket对象

客户端:socket 如果直接关闭的话,可以直接通过异常来捕捉

但是如果是通过shutdown的话,本地客户端不会立即关闭,而是往服务端发送空包,表示

自己已经关闭,并等待服务端响应,会等一定的时间,超时后再关闭socket。

服务端:可以通过获取的包的长度是0,也就是空包,则直接退出循环,并关闭socket

扩展(发信息,抖动,文件,)

发送数据中:第一个字节如果是0,代表字符串

如果是1:代表闪屏

如果是2:代表文件

给数据数组添加 数据类型的标志位

byte[] realData = new byte[data.Length +1];

realData[0] = 0;设置是字符串类型

把一个块拷贝到另外一个

Buffer.BlockCopy(data,0,realData,1,data.Length);

客户端连接服务器:

1.创建Socket

clientSocket=newSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);直接连接服务器:只要下面的方法连接服务没有出现异常,那么就代表连接成功。

clientSocket.Connect(IPAddress.Parse(this.txtIp.Text),int.Parse(this.txtPort.Text));

2.接受服务器发送的消息:

创建新线程不断接受服务器发来的消息(首先判断第一个字节是0,1,2)

recieveThread = new Thread(new ParameterizedThreadStart(this.ProcessReciveData));

recieveThread.IsBackground = true;

recieveThread.Start(null);

3.窗体关闭之前,先关闭Socket

recieveThread.Abort();//关闭一直在接收数据的线程

if (clientSocket.Connected)

{

clientSocket.Shutdown(SocketShutdown.Both);

clientSocket.Close();

}

HTTP协议简单流程:

在浏览器中输入地址,将数据封装成了HTTP协议里面规定的请求数据的格式:

GET/Login/LogOn HTTp/1.1

Accept:text/html,application/xhtml+xml,*/*

Accept-Language:zh-CN

User-Agent:MOzilla/5.0(compatible;MSIE 9.0);

Qdesk 2.5.1270.201; Windows NT 6.1; Trident/5.0)

Accept-Encoding:gzip,deflate

Host:localhost:8094

Connection:Keep-Alive

Cookie:txtName=ertertre;

通过Socket发送到服务端,服务端对报文经行解析,处理,响应,再发送到客户端,

客户端解析响应保温,然后渲染html页面和css,js等;

托管和非托管

托管:中间代码交给clr解析成编译成操作系统能识别的二进制码的代码

非托管:直接将二进制码交给操作系统化内核执行的代码

线程:

初始化线程非常消耗资源(显示的东西少时,不建议创建线程,可以用线程池)

前台和后台线程

1.默认线程是一个主线程,是一个前台线程

2.前台线程都执行完毕才能结束进程

3.一般情况下使用的线程的时候都要用后台线程

线程的一些方法

1.设置后台线程

thread.IsBackground=true;//如果设置为true表示当前线程为后台线程:当程序中所有的前台线程都退出之后,那么主进程就退出了,后台线程不阻塞退出

2.给线程取名

thread.Name="给开发人员用的,用来区分不同的线程";

3.准备好,让操作系统执行

thread.Start();//只是告诉操作系统:我怎备好了

4.建议的设置线程的优先级(具体还的由操作系统决定,操作系统的线程优先级是最高的)

thread.priority=Threadpriority.AbveNormal;//给当前线程设置一个优先级

5. 关闭线程  (关闭的线程就不能在重新进行使用)

第一种

这种一般是在线程中出现了异常,正常情况不能关闭的时候(不建议使用)

出现异常的时候会很大的影响程序的性能(这个关闭就不能在使用了)

thread.Abort();//直接关闭线程:内部会抛出一个异常,尽量不要用,这样会导致系统内部抛出异常,但不会导致程序崩溃,clr帮我们捕获了此异常

第二种

控制信号体关闭线程,即设置一个标签控制线程的停止,而不是调用上面的那个方法,这样线程还能进行使用

6.设置等待时间

Thread.Sleep(2000);

7.主线程等待子线程结束后在执行,可以填写参数规定等待时间

thread.Join();//那个线程调用此方法,就让哪个线程等待thread线程。

8.得到当前线程的id号

Thread.currentThread.ManagedThreadId;

线程的使用

1.线程的简单的写法

new Thread(()=>

{

Console.writeLine("ddd");

}).Start();

2.带参数的线程

2.1传入委托的类型

ParameterizedThreadstrt

//pubic delegate void ParameterizedThreadStart(object obj);

2.2实例化一个

Thread thread=new Thread(delegate(object obj){ Console.writeLine(obj.Tostring());});

2.3通过start方法给委托传值

thread.start(4);

异步委托(使用的是线程池)

异步委托就是相当于创建一个新的线程执行这个委托,因为创建一个线程的时候,委托的类型的固定的,异步委托,委托类型由自己决定,而且这个线程由线程池提供(是后台线程)节省资源

异步委托的使用

第一种

1.声明一个委托类型

public delegate int AddDel(int a,int b);

2.定义一个这种委托类型的方法

static int AddDemo(int a, int b)

{

return a+b;

}

3.让这个委托类型方法异步

AddDel addDel=new AddDel(addDemo);

//addDel(4,5);//这样是由当前执行此代码的线程执行 委托指向的方法

var result= addDel.BeginInvoke(4,5,null,null);//启动一新线程【后台线程,此线程由线程池提供】,新的线程回调函数指向委托的方法

//new Tread(AddDemo)

4.Result是异步委托中的一些信息

//去拿另外一个线程执行方法的结果

int retval=addDel.EndInvoke(result);//阻塞当前主线程,直到子线程执行完成并返回值。

第二种

1.在异步中获取返回值 (异步委托函数运行完,执行回调函数)

addDel.BeginInvoke(5,6,new AsyncCallback(ProcessAfterFunExcute),"s")

2.回调函数的过程:把上边异步方法的返回值的相关的信息,传入到回调函数中作为参数

static void ProcessAfterFunExcute(IAsyncResult result)

{

//在异步的委托的方法执行完成之后,自动来调用此方法。调用此方法的线程是新的线程

AsyncResult funAsyncResult=(AsyncResult) result;

AddDel del=(AddDel) funAsyncResult.AsyncDelegate;//拿到异步的委托的实例

var retval=del.EndInvoke(funAsyncResult);

3.打印"s"

//拿到传来的值

Console.writeLine(funAsynResult.Asyncstate.Tostring());

并发和异步

并发:同一时间执行一个代码或动作

异步:并不是并发,是时间片轮转

摇奖

动态创建的控件默认只能由创建他的线程使用,但是可以设置,别的线程访问

//禁止 线程操作控件进行检查

Control.checkForIllegalCrossThreadCalls=false;

也可以不设置检查,进行判断(专业的方式,判断当前的控件是否是当前的线程创建的)

用invoke方法

foreach(var label in lbList)

{

if(label.InvokeRequired)//InvokeRequired属性就是帮我们判断当前线程跟控件之间的关系,如果为true 代表:当前控件不是线程创建的,那么需要进行invoke。如果为false,那么代表当前控件就是当前线程创建的,直接用就行了,不需要Invoke

{

//invoke方法对控件的操作

label.Invoke(new Action<Label,string>(this.setText),label,r.Next(0,10).ToString());//invoke后面的传来的方法体,由创建Lable的线程执行

}

else

{

//如果当前lable控件就是执行当前代码的线程创建的话,没问题的

label.Text=r.Next(0,10).ToString();

}

、、Control:跨线程方法,使用第一种方式,禁止校验跨线程访问的方式

}

Thread.Sleep(100);

线程池

线程池:为了提高线程使用效率,节省创建线程消耗的资源,提高线程重复利用率,避免用户适应的线程每次都重新创建和分配线程

线程池的内部结构

包括,工作项队列(创建线程池时,传入的方法体委托其实放在工作项队列中,不使用的情况下是先进先出。但当调用到线程中执行后,工作项队列多种的委托执行的顺序就是不确定的,无序的),和线程(也包含线程的工作项队列,后进先出,当这个工作线程的栈空的时候,去公共的队列中去取几个工作项)

线程池的使用

Threadpool.QueueuserworkItem(0=>{console.writeLiine(o.Tostring());},“1”);

模拟对象池

生产者和消费者,利用lock的机制实现了同步,也就是一个线程在使用修改数据的时候别的线程不能使用,必须等解锁以后才能使用

生产消费内部实现的过程

在应用程序域的堆中,每个对象都有下面内容:类空间(自己的属性和方法,属于当前的对象),同步索引块(默认为-1,有了lock后相当于加上了一个索引值,指向同步索引数组中的一个变量,lock结束又变回-1),类型指针(每个类的实例的类型指针指向的类型对象,指向类型信息)

上一篇:js基础知识易错点(一)


下一篇:AFnetworking3.1的基本使用