http://cxhblog.blog.sohu.com/41930676.html

一、Socket通信:

Delphi在ScktComp单元中对WinSock进行了封装,该单元提供了TAbstractSocket、TClientSocket、TClientWinSocket、TCustomSocket、TCustomWinSocket、TCustomServerSocket 、TServerClientThread、TServerWinSocket、  TServerClientWinSocket、、TServerSocket、TWinSocketStream等相关的类。

它的继承关系为:

                  

TAbstractSocket类是所有Socket组件的基类。

TCustomWinSocket类是所有WinSock对象的基类。

TClientSocket类用于管理客户Socket连接。

TClientWinSocket类:客户Socket组件(TClientSocket)使用它来为客户应用管理WinSock API调用。

TServerSocket类为TCP/IP服务器管理服务器Socket连接。

TServerClientWinSocket类:服务器Socket组件(TServerSocket)使用它管理到一个客户Socket的WinSock API调用。

TServerWinSocket类:服务器Socket组件(TServerSocket)使用它为TCP/IP监听连接管理WinSock API调用。

TWinSocketStream类:在线程阻塞工作模式下提供到Socket连接的读写服务。

TServerClientThread类:用于为每一个到客户Socket的独立的连接创建一个线程。

要点

TServerWinSocket类用于管理服务器端的Socket,TClientWinSocket类用于管理客户端Socket。因为我们用控件的话,放置的控件是标准的Socket控件不能为Windows平台直接管理和使用,所以要用TServerWinSocket和TClientWinSocket来分别进行管理使其转变为WinSock以便Windows平台更好的控制和使用。

服务器端Socket使用TServerClientWinSocket管理一个到客户Socket的连接。TServerClientWinSocket与TServerWinSocket的区别是:当把一个TServerSocket组件放置到一个窗体或数据模块上并进入监听状态后,就自动创建了TServerWinSocket,而只有当服务器Socket监听到一个客户Socket的连接请求时并接受了请求后,才创建一个TServerClientWinSocket。当客户Socket的连接断开时,自动删除相应的TServerClientWinSocket。TServerClientWinSocket有一个ServerWinSokcet属性,它返回处监听状态的服务器端Socket对象(TServerWinSocket)。

当你把服务端设置成stthreadblocking的阻塞方式的时候,OnRead根本不会被触发,OnRead是在非阻塞的异步的时候才会被触发.正确的方法(阻塞)是定义一个ClientThread的线程类,在ServerSocketGetThread的时候创建一个线程,处理客户端请求..这样就可以支持多个客户端同时连接和收发封包. 至于客户端,用非阻塞的方式就可以了.

疑问:

      1、ClientSocket的ClientType为ctNonBlocking ctBlocking的区别?
      2、ServerSocket的ServerType为stNonBlocking,stThreadBlocking的区别?

解答:

     1、ctNonBlocking(非阻塞):它是异步进行读写操作,因此数据的传输不会阻塞应用程序中其他的代码执行,使用非阻断型连接时,当连接的另一端试图读写信息时,会触发OnReceive和OnSend事件来通知你的Socket,从Socket连接中读取信息需要调用ReceiveBuf或ReceiveIn方法,写信息需要调用SendBuf,SendStream或SendIn方法。当连接阻断后,Socket必须主动在已建立的连接上读写信息,而不是被动地等待Socket连接来通知。如果想控制何时开始读或写,请使用阻断型Socket。它是处理机制是通过消息处理。ctBlocking(阻断):此为阻断式。

2、对于服务器端Socket,将BlockMode属性设置为bmBlocking或是bmThreadBlocking都可以建立阻断型连接。当Socket正在等待完成某个请求的读写操作时,阻断型连接会拦截住所有其他代码的执行。当属性是stThreadBlocking(线程阻塞模式)时,服务器端Socket组件总会为每一个客户端连接生成一个新的执行线程。当属性为bmBlocking时,程序被阻塞,直到一个新的连接建立。要在OngetThread中生成TServerClientThread来处理数据,这时ThreadCacheSize提供了一个线程池的功能。

二、多线程编程:

Delphi的VCL有一个缺陷,就是不支持多个线程同时访问它。如果线程中要访问VCL对象可以用Synchronize来实现,它用Method参数指定的方法去访问VCL对象,实际上线程本人并不调用这个方法,而是通知主线程调用这个方法,主线程一次只能收到一个通知,这样就避免了对VCL对象并发访问。(注:任何继承VCL中定义的类的对象就是VCL对象)

编写线程代码时,必须要考虑其他线程的影响,具体的说:一方面线程互斥,另一方面就是线程同步。互斥就是要解决多线程同时访问一个全局变量,同步就是解决线程执行顺序的问题(一个线程结束之后,自动唤醒等待它的运算结果的其它线程)。

线程互斥:要避免多个线程并发访问全局变量时发生冲突,VCL中提供了三种解决方法:锁定对象、设置临界段、共享读—独占写。

1、锁定对象:一些对象本身就有Lock和UnLock方法,线程在操作这类对象时可以用这两个方法,还有一些线程安全的对象,如TCanvas和TThreadlist,它们自身就有一种机制来保持线程安全,如TCanvas可以自动使用Lock和Unlock来锁定和解锁。

2、设置临界段:如果没Lock方法,可以考虑临界段,它象一个门,同一时刻内只允许一个线程访问。它是通过创建一个TCriticalSection的全局实例来实现的。它有两个方法:Acquire(锁定)和Release(开放)。注意,只有所有线程都是通过临界段访问与之相连的全局内存,这种方法才能起作用。

3、共享读—独占写:设置临界体段的方法有一个缺点,就是在同一时刻只能有一个线程访问全局变量,而实际上我们不是总是改全局变量,很多情况只是读,这并不对内存造成错误,这种情况我们可采用TMultiReadExclusiveWriteSynchronizer对象来实现多个线程同时读全局变量,而只允许一个线程改。与设置临界段相同的是,也要求所有访问都采用这个对象,它有如下方法:BeginRead,EndRead,BeginWrite及EndWrite。

线程同步:如果一个线程必须等到其他线程的任务结束才能够继续,那么可以通知它暂时挂起。具有两种方式:

1、  等待其他线程结束,调用WaitFor方法可以实现。

2、  等待一个作业完成,有时希望等待一个线程完成一些操作,而不是等待一个线程执行结束。如果是这样,则需要一个事件对象TEvent,事件对象必须为全局对象,它对所有的线程都是可见的。当一个线程完成了其他线程所要求的任务,它就调用TEvent.SetEvent方法打开一个标志,其他线程可以检查这个标志,从而得知需要的任务已经完成。如果要关掉这个标志,则应调用ResetEvent方法。

疑问:

线程局部变量与普通变量的区别?threadvar

答:线程的局部变量要想被线程中调用的函数来访问,就要用threadvar来声明这个变量,否则线程中调用的外部函数就不能访问这个变量,这类变量只能被线程内的函数来访问.

Delphi Socket通信及多线程编程总结的更多相关文章

  1. Linux下socket通信和多线程

    服务端socket流程:socket() –> bind() –> listen() –> accept() –> 读取.发送信息(recv,send等) 客户端socket流 ...

  2. Socket通信和多线程的总结

    1.ServerSocket进行多线程接收 package com.yh.chat; import java.io.IOException; import java.net.ServerSocket; ...

  3. java Socket和ServerSocket多线程编程

    这是在一本java教材上看到的,做了点修改.具体本教材记不清楚了,Sorry.放在这里,只是让自己需要的时候能够容易找到. 程序分两部分,服务端和客户端.先把服务端运行起来,在运行客户端.整个过程就是 ...

  4. Java的Socket通信(多线程)(1)

    如图: 思路: ①首先创建服务器端Socket,指定并侦听某一个端口,然后循环监听开始等待客户端的连接…. ②创建客户端socket,指定服务器地址和端口,然后获取输出流,向服务器端发送请求,并关闭s ...

  5. 并发编程~~~多线程~~~计算密集型 / IO密集型的效率, 多线程实现socket通信

    一 验证计算密集型 / IO密集型的效率 IO密集型: IO密集型: 单个进程的多线程的并发效率高. 计算密集型: 计算密集型: 多进程的并发并行效率高. 二 多线程实现socket通信 服务器端: ...

  6. Win32多线程编程(3) — 线程同步与通信

      一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线 ...

  7. 转发 Delphi中线程类TThread 实现多线程编程

    Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchr ...

  8. Socket 多线程编程

    前面一片学习了TCP/IP的基础网络编程,并给出了简单的服务端与客户端通信交互的例子.还介绍了UPC的通信例子. 这次学习TCP/IP的多线程编程.因为涉及到TCP/IP一般都是多线程,服务端会一直监 ...

  9. java网络编程Socket通信详解

    Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socket.像大家熟悉的QQ.MSN都使用了Socket相关的技术. ...

随机推荐

  1. zufe 蓝桥选拔

    https://zufeoj.com/contest.php?cid=1483 问题 A: A 代码: #include <bits/stdc++.h> using namespace s ...

  2. [Java文件操作] 将素数输出到文件

    [要求]编写程序求出10万以内的所有素数,并将这些素数输出到一个文本文件中,每行文本只包含一个素数数据. import java.util.*; import java.io.*; public cl ...

  3. 【bzoj1999】[Noip2007]Core树网的核 树的直径+双指针法+单调队列

    题目描述 给出一棵树,定义一个点到一条路径的距离为这个点到这条路径上所有点的距离的最小值.求一条长度不超过s的路径,使得所有点到这条路径的距离的最大值最小. 输入 包含n行: 第1行,两个正整数n和s ...

  4. 【bzoj1001】[BeiJing2006]狼抓兔子 最小割+对偶图+最短路

    题目描述 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: ...

  5. HTML5<canvas>标签:使用canvas元素在网页上绘制渐变和图像(2)

    详细解释HTML5 Canvas中渐进填充的参数设置与使用,Canvas中透明度的设置与使用,结合渐进填充与透明度支持,实现图像的Mask效果. 一:渐进填充(Gradient Fill) Canva ...

  6. [HAOI2010]计数

    题面在这里 description 你有一组非零数字(不一定唯一),你可以在其中插入任意个0,这样就可以产生无限个数. 比如说给定{1,2},那么可以生成数字12,21,102,120,201,210 ...

  7. [Leetcode] distinct subsequences 不同子序列

    Given a string S and a string T, count the number of distinct subsequences of T in S. A subsequence ...

  8. linux下搭建redis并解决无法连接redis的问题

    以前公司在开发阶段连接的redis一直是正式环境中的,最近老大让我在搭建一个局域网内的redis用于开发阶段时连接使用,搭建过程中也遇到了一些问题,还好已经解决了,在这里记录一下. 首先是搭建redi ...

  9. 微信小程序使用Socket

    首先,一个小程序同时只能有一个WebSocket连接,如果当前已经存在一个WebSocket连接,会关闭当前连接,并重新建立一个连接. 其次,如果使用了appID,协议必须是 wss://... 最近 ...

  10. mysql5.7.22以上版本忘记密码时这样修改

    1.关闭mysql服务 net stop mysql 2.找到mysql安装路径找到 my.ini 打开在 [mysqld] 下添加 skip-grant-tables 跳过密码校验 3.登陆mysq ...