在多线程中使用UDP
来自:painboy, 时间:2004-8-8 11:34:40, ID:2754268

type TUdpThread = class(TThread)
 private
   FData     : PChar;        //数据区
   FBytes    : Integer;      //数据区大小
   FFromIP   : string;       //UDP的源地址
   FFromPort : Integer;      //UDP的源端口
 public
   constructor Create(Buffer: PChar; NumberBytes: Integer; FromIP: String; Port: Integer);
 protected
   procedure Execute; override;
end;

procedure TForm1.Button1Click(Sender: TObject);
var Buffer : array[0..1024] of char;
begin
 strcopy(buffer,pchar(Edit1.Text));
 UdpSend.ReportLevel := Status_Basic;
 UdpSend.RemotePort := 4000;
 UdpSend.RemoteHost := '127.0.0.1';
 UdpSend.Sendbuffer(buffer,256);
end;

constructor TUdpThread.Create(Buffer: PChar; NumberBytes: Integer; FromIP: String; Port: Integer);
begin
 inherited Create(True);

FData     := Buffer;
 FBytes    := NumberBytes;
 FFromIP   := FromIP;
 FFromPort := Port;

FreeOnTerminate := True;
 Resume;
end;

procedure TUdpThread.Execute;
var Buffer : PChar;
   BackTo : array[0..1] of char;
   str    : string;
   myUDP  : TNMUDP;
begin
 str := inttostr(GetTickCount)+' : ';
 GetMem(Buffer, FBytes+1);
 CopyMemory(Buffer, FData, FBytes);

Randomize;                              
 Sleep(Random(5000));                    
 Form1.Memo1.Lines.Add(str+Buffer);  
 //其实以上几句改为你自己的处理代码就是了    
 
 FillChar(BackTo, 2, f);
 myUDP := TNMUDP.Create(Nil);
 myUDP.RemoteHost  := FFromIP;
 myUDP.ReportLevel := Status_Basic;
 myUDP.LocalPort   := 4000;

myUDP.SendBuffer(BackTo, 2);            //回个响应包给对方

FreeMem(Buffer, FBytes+1);
 FreeMem(FData, FBytes);
end;

procedure TForm1.UdpRecvDataReceived(Sender: TComponent;
 NumberBytes: Integer; FromIP: String; Port: Integer);
var Buffer : PChar ;
begin
 GetMem(Buffer, NumberBytes);
 UdpRecv.ReadBuffer(Buffer^, NumberBytes);                //接收数据
 TUdpThread.Create(Buffer, NumberBytes, FromIP, Port);    //将数据交给子线程处理
end;

procedure TForm1.UdpSendDataReceived(Sender: TComponent;
 NumberBytes: Integer; FromIP: String; Port: Integer);
var Buffer : PChar ;
begin
 GetMem(Buffer, NumberBytes);
 UdpSend.ReadBuffer(Buffer^, NumberBytes);
 FreeMem(Buffer, NumberBytes);
end;

来自:painboy, 时间:2004-8-8 13:56:05, ID:2754370
SORRY,看错题了。你是说要在线程里收发数据。用API重写了一下,D5下通过了。

type TUdpThread = class(TThread)
 private
   FSocket : TSocket;
 public
   constructor Create;
 protected
   procedure Execute; override;
   function CanRead(Socket : TSocket; Timeout: Integer): Boolean;
end;

constructor TUdpThread.Create;
begin
 inherited Create(True);
 FreeOnTerminate := True;
 Resume;
end;

function TUdpThread.CanRead(Timeout: Integer): Boolean;
var
 TimeV: TTimeVal;
 FDSet: TFDSet;
 X    : integer;
begin
 TimeV.tv_usec := (Timeout mod 1000) * 1000;
 TimeV.tv_sec := Timeout div 1000;
 FDSet.fd_count := 1;
 FDSet.fd_array[0] := FSocket;
 X := Select(0, @FDSet, nil, nil, @TimeV);
 Result := X>0;
end;

procedure TUdpThread.Execute;
var
 wsaD      : WSADATA;
 sa        : TSockAddrIn;
 nLen,nFrom: Integer;
 UdpBuffer : array[0..1023] of Char;
begin
 WSAStartup(01, wsaD);
 FSocket := Socket(AF_INET, SOCK_DGRAM, 0);
 if (FSocket <> INVALID_SOCKET) then begin
   sa.sin_family:= AF_INET;
   sa.sin_port:= htons(4096);
   sa.sin_addr.S_addr:= inet_addr('127.0.0.1');
   nLen:= SizeOf(sa);
   bind(FSocket, sa, nLen);
   While not Terminated do
     if CanRead(10) then begin                                 //检查是否有数据可接收
       FillChar(UdpBuffer, 1024, 0);
       nFrom := SizeOf(sa);
       RecvFrom(FSocket, UdpBuffer, nLen, 0, sa, nFrom);       //接收数据

Form1.Memo1.Lines.Add(inet_ntoa(sa.sin_addr)+' : '+UdpBuffer);

FillChar(UdpBuffer, 2, f);
       nFrom := SizeOf(sa);
       SendTo(FSocket, UdpBuffer, 2, 0, sa, nFrom);            //应答
     end  else begin
       //暂时没有数据来,你可以干点别的事情  :)
     end;
   CloseSocket(FSocket);
 end;
 WSACleanUp;
end;

//
//                                                                                      //
//        上面的线程是用WINSOCKET API写的,没做差错检查,但你说的功能已经实现           //
//                                                                                      //
//

procedure TForm1.Button1Click(Sender: TObject);              //这里 UdpSend是个TNMUDP控件
var Buffer : array[0..1024] of char;
begin
   strcopy(buffer,'Hello!');
   UdpSend.ReportLevel := Status_Basic;
   UdpSend.RemotePort := 4096;
   UdpSend.RemoteHost := '127.0.0.1';
   UdpSend.Sendbuffer(buffer,256);
end;

procedure TForm1.UdpSendDataReceived(Sender: TComponent;
 NumberBytes: Integer; FromIP: String; Port: Integer);
var Buffer : PChar ;
begin
 GetMem(Buffer, NumberBytes);
 UdpSend.ReadBuffer(Buffer^, NumberBytes);
 FreeMem(Buffer, NumberBytes);
 Memo1.Lines.Add(Inttostr(NumberBytes)+ ' Bytes');
end;

来自:乡村月光, 时间:2004-8-8 14:45:58, ID:2754430
我有API的代码,一个转发服务器,一个队列发送器,一个队列接收器,用起来很方便,有人要就贴

来自:乡村月光, 时间:2004-8-9 22:23:59, ID:2756448


unit UDPNet;

interface
uses Windows, Messages, SysUtils, Variants, Classes, Winsock;

// 为了提高效率,本单元所有的地址都使用winsock内部格式,和习惯IP之间用AddrToIP和IPToAdr转换!
const
 UDPACKETSIZE = 512; // 最大UDP包大小
 UDPXHEADSIZE = 8;   // 数据包头大小
 UDPXDATASIZE = UDPACKETSIZE - UDPXHEADSIZE ; // 最大数据包大小

UDPXDATAFLAG = AC5; // 转发数据包头标志

WM_TERMINATE = WM_USER + 100; // 结束线程
 WM_SENDDATA  = WM_USER + 101; // 发送数据

type
 TSyncSignal = class(TObject) // 线程安全信号
 private
   FSignal: Boolean;
   FCritical: _RTL_CRITICAL_SECTION;
   function GetSignal: Boolean;
 public
   constructor Create(IniState: Boolean);
   destructor Destroy; override;
   procedure Reset;
   property IsSafe: Boolean read GetSignal;
 end;

ESocketError = class(Exception);

TSyncUDPSocket = class(TObject) // 封装API
 protected
   FHandle: TSocket;
   FLastError: Integer;
   function GetBroadcast: Boolean;
   function GetReuseAddr: Boolean;
   function GetRecvBufSize: Integer;
   function GetSendBufSize: Integer;
   procedure SetBroadcast(Value: Boolean);
   procedure SetReuseAddr(Value: Boolean);
   procedure SetRecvBufSize(Value: Integer);
   procedure SetSendBufSize(Value: Integer);
 public
   constructor Create;
   destructor Destroy; override;
   function RecvBuffer(var Buffer; Len: Integer): Integer;
   function RecvFrom(var Buffer; Len: Integer; var Addr: Integer; var Port: Word): Integer;
   function ByteCanRead: Integer;
   function SendBuffer(var Buffer; Len: Integer): Integer;
   function SendTo(Addr: Integer; Port: Word; var Buffer; Len: Integer): Integer;
   function WaitForData(TimeOut: Integer): Boolean;
   procedure Bind(Addr: Integer; Port: Word);
   procedure Connect(Addr: Integer; Port: Word);
   procedure CreateSocket;
   procedure GetLocalHost(var IP: string; var Port: Word);
   procedure GetRemoteHost(var IP: string; var Port: Word);
   property Broadcast: Boolean read GetBroadcast write SetBroadcast;
   property Handle: TSocket read FHandle write FHandle;
   property LastError: Integer read FLastError;
   property ReuseAddr: Boolean read GetReuseAddr write SetReuseAddr;
   property SizeRecvBuffer: Integer read GetRecvBufSize write SetRecvBufSize;
   property SizeSendBuffer: Integer read GetSendBufSize write SetSendBufSize;
 end;

TUDPXDataBuffer = packed record // 转发数据包
   Flag: Word;
   Port: Word;
   Addr: Integer;
   Data: array [0..UDPXDATASIZE-1] of Byte;
 end;

TUDPXServerThread = class(TThread) // 数据转发服务器
 protected
   FUDPSock: TSyncUDPSocket;
   FUDPort: Word;
 public
   constructor Create(Port: Word);
   destructor Destroy; override;
   procedure Execute; override;
 end;

TUDPQueData = packed record  // 队列数据
   Addr: Integer;
   Port: Word;
   Len: Word;
   Data: array [0..UDPACKETSIZE-1] of Byte;
 end;
 TUDPQueBuffer = array [0..1] of TUDPQueData;
 PUDPQueBuffer = ^TUDPQueBuffer;

TUDPDataQue = record // 队列
   Header, Tail, BufSize: Integer;
   IsFull: Boolean;
   Queue: PUDPQueBuffer;
 end;

TUDPReceiver = class;
 TUDPDataNotify = procedure(Sender: TUDPReceiver; const Data: TUDPQueData) of object;

TUDPReceiver = class(TThread) // 接收器
 protected
   FUDPSock: TSyncUDPSocket;
   FOnData: TUDPDataNotify;
 public
   constructor Create(Sock: TSyncUDPSocket);
   procedure Execute; override;
   property OnData: TUDPDataNotify read FOnData write FOnData;
   property UDPSock: TSyncUDPSocket read FUDPSock write FUDPSock;
 end;

TUDPQueSender = class(TThread) // 队列发送器,通过消息WM_TERMINATE结束
 protected
   FUDPSock: TSyncUDPSocket;
   FBuffer: TUDPDataQue;
   FSync: TSyncSignal;
 public
   constructor Create(Sock: TSyncUDPSocket; BufSize: Integer);
   destructor Destroy; override;
   function AddData(Addr: Integer; Port: Word; const Header; HLen: Word;
            const Data; DLen: Word): Boolean; // 要发送数据调用本函数
   procedure Execute; override;
   property Buffer: TUDPDataQue read FBuffer;
   property UDPSock: TSyncUDPSocket read FUDPSock write FUDPSock;
 end;

function AddrToIP(Addr: Integer): string;
function IPToAddr(const IP: string): Integer;

implementation

constructor TSyncSignal.Create(IniState: Boolean);
begin
 inherited Create;
 InitializeCriticalSection(FCritical);
 FSignal := IniState;
end;

destructor TSyncSignal.Destroy;
begin
 DeleteCriticalSection(FCritical);
 inherited Destroy;
end;

function TSyncSignal.GetSignal: Boolean;
begin
 EnterCriticalSection(FCritical);
 Result := FSignal;
 FSignal := False;
 LeaveCriticalSection(FCritical);
end;

procedure TSyncSignal.Reset;
begin
 FSignal := True;
end;

constructor TSyncUDPSocket.Create;
begin
 inherited Create;
 FLastError := 0;
 FHandle := INVALID_SOCKET;
end;

destructor TSyncUDPSocket.Destroy;
begin
 if FHandle <> INVALID_SOCKET then CloseSocket(FHandle);
 inherited Destroy;
end;

function TSyncUDPSocket.GetBroadcast: Boolean;
var m, n: Integer;
begin
 FLastError := 0;
 n := Sizeof(Integer);
 if GetSockOpt(FHandle, SOL_SOCKET, SO_BROADCAST, @m, n) <> 0 then
 begin
   FLastError := WSAGetLastError;
   Result := False;
 end
 else Result := m <> 0;
end;

function TSyncUDPSocket.GetReuseAddr: Boolean;
var m, n: Integer;
begin
 FLastError := 0;
 n := Sizeof(Integer);
 if GetSockOpt(FHandle, SOL_SOCKET, SO_REUSEADDR, @m, n) <> 0 then
 begin
   FLastError := WSAGetLastError;
   Result := False;
 end
 else Result := m <> 0;
end;

function TSyncUDPSocket.GetRecvBufSize: Integer;
var n: Integer;
begin
 n := SizeOf(Result);
 FLastError := 0;
 if GetSockOpt(FHandle, SOL_SOCKET, SO_RCVBUF, @Result, n) <> 0 then
 begin
   FLastError := WSAGetLastError;
   Result := -1;
 end;
end;

function TSyncUDPSocket.GetSendBufSize: Integer;
var n: Integer;
begin
 n := SizeOf(Result);
 FLastError := 0;
 if GetSockOpt(FHandle, SOL_SOCKET, SO_SNDBUF, @Result, n) <> 0 then
 begin
   FLastError := WSAGetLastError;
   Result := -1;
 end;
end;

procedure TSyncUDPSocket.SetBroadcast(Value: Boolean);
var n: Integer;
begin
 FLastError := 0;
 if Value then n := -1 else n := 0;
 if SetSockOpt(FHandle, SOL_SOCKET, SO_BROADCAST, @n, SizeOf(Integer)) <> 0 then
   FLastError := WSAGetLastError;
end;

procedure TSyncUDPSocket.SetReuseAddr(Value: Boolean);
var n: Integer;
begin
 FLastError := 0;
 if Value then n := -1 else n := 0;
 if SetSockOpt(FHandle, SOL_SOCKET, SO_REUSEADDR, @n, SizeOf(Integer)) <> 0 then
   FLastError := WSAGetLastError;
end;

procedure TSyncUDPSocket.SetRecvBufSize(Value: Integer);
begin
 FLastError := 0;
 if SetSockOpt(FHandle, SOL_SOCKET, SO_RCVBUF, @Value, SizeOf(Integer)) <> 0 then
   FLastError := WSAGetLastError;
end;

procedure TSyncUDPSocket.SetSendBufSize(Value: Integer);
begin
 FLastError := 0;
 if SetSockOpt(FHandle, SOL_SOCKET, SO_SNDBUF, @Value, SizeOf(Integer)) <> 0 then
   FLastError := WSAGetLastError;
end;

function TSyncUDPSocket.ByteCanRead: Integer;
var n: Integer;
begin
 FLastError := 0;
 if IoctlSocket(FHandle, FIONREAD, n) = 0 then Result := n
 else begin
   FLastError := WSAGetLastError;
   Result := 0;
 end;
end;

function TSyncUDPSocket.WaitForData(TimeOut: Integer): Boolean;
var tv: TTimeVal;
   pt: PTimeVal;
   n: Integer;
   fs: TFDSet;
begin
 if TimeOut < 0 then pt := nil else
 begin
   tv.tv_sec := TimeOut div 1000;
   tv.tv_usec := (TimeOut mod 1000) * 1000;
   pt := @tv;
 end;
 FD_ZERO(fs);
 FD_SET(FHandle, fs);
 n := select(0, @fs, nil, nil, pt);
 if n = SOCKET_ERROR then
 begin
   FLastError := WSAGetLastError;
   n := 0;
 end
 else FLastError := 0;
 Result := n > 0;
end;

function TSyncUDPSocket.RecvBuffer(var Buffer; Len: Integer): Integer;
begin
 FLastError := 0;
 Result := WinSock.recv(FHandle, Buffer, Len, 0);
 if Result = SOCKET_ERROR then FLastError := WSAGetLastError;
end;

function TSyncUDPSocket.RecvFrom(var Buffer; Len: Integer; var Addr: Integer; var Port: Word): Integer;
var a: TSockAddr;
   n: Integer;
begin
 FLastError := 0;
 Result := WinSock.RecvFrom(FHandle, Buffer, Len, 0, a, n);
 Port := ntohs(a.sin_port);
 Addr := a.sin_addr.s_addr;
 if Result = SOCKET_ERROR then FLastError := WSAGetLastError;
end;

function TSyncUDPSocket.SendBuffer(var Buffer; Len: Integer): Integer;
begin
 FLastError := 0;
 Result := WinSock.send(FHandle, Buffer, Len, 0);
 if Result = SOCKET_ERROR then FLastError := WSAGetLastError;
end;

function TSyncUDPSocket.SendTo(Addr: Integer; Port: Word; var Buffer; Len: Integer): Integer;
var a: TSockAddr;
begin
 FLastError := 0;
 a.sin_family := AF_INET;
 a.sin_port := htons(Port);
 a.sin_addr.s_addr := Addr;
 Result := WinSock.SendTo(FHandle, Buffer, Len, 0, a, Sizeof(TSockAddr));
 if Result = SOCKET_ERROR then FLastError := WSAGetLastError;
end;

procedure TSyncUDPSocket.Bind(Addr: Integer; Port: Word);
var a: TSockAddr;
begin
 if FHandle = INVALID_SOCKET then
 begin
   CreateSocket;
   if FLastError <> 0 then Exit;
 end;
 FLastError := 0;
 a.sin_family := AF_INET;
 a.sin_port := htons(Port);
 a.sin_addr.s_addr := Addr;
 if WinSock.Bind(FHandle, a, Sizeof(TSockAddr)) = SOCKET_ERROR then
   FLastError := WSAGetLastError;
end;

procedure TSyncUDPSocket.Connect(Addr: Integer; Port: Word);
var a: TSockAddr;
begin
 if FHandle = INVALID_SOCKET then
 begin
   CreateSocket;
   if FLastError <> 0 then Exit;
 end;
 FLastError := 0;
 a.sin_family := AF_INET;
 a.sin_port := htons(Port);
 a.sin_addr.s_addr := Addr;
 if WinSock.Connect(FHandle, a, Sizeof(TSockAddr)) = SOCKET_ERROR then
   FLastError := WSAGetLastError;
end;

procedure TSyncUDPSocket.CreateSocket;
begin
 FLastError := 0;
 FHandle := Socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 if FHandle = INVALID_SOCKET then FLastError := WSAGetLastError;
end;

procedure TSyncUDPSocket.GetLocalHost(var IP: string; var Port: Word);
var addr: TSockAddr;
   len: Integer;
begin
 FillChar(addr, Sizeof(TSockAddr), 0);
 len := Sizeof(TSockAddr);
 GetSockName(FHandle, addr, len);
 IP := inet_ntoa(addr.sin_addr);
 Port := ntohs(addr.sin_port);
end;

procedure TSyncUDPSocket.GetRemoteHost(var IP: string; var Port: Word);
var addr: TSockAddr;
   len: Integer;
begin
 FillChar(addr, Sizeof(TSockAddr), 0);
 len := Sizeof(TSockAddr);
 GetPeerName(FHandle, addr, len);
 IP := inet_ntoa(addr.sin_addr);
 Port := ntohs(addr.sin_port);
end;

constructor TUDPXServerThread.Create(Port: Word);
begin
 inherited Create(True);
 FUDPort := Port;
end;

destructor TUDPXServerThread.Destroy;
begin
 FUDPSock.Free;
 inherited Destroy;
end;

procedure TUDPXServerThread.Execute;
var n, a: Integer;
   p: Word;
   buf: TUDPXDataBuffer;
begin
 FUDPSock := TSyncUDPSocket.Create;
 FUDPSock.Bind(0, FUDPort);
 while not Terminated do
 begin
   if FUDPSock.WaitForData(100) then
   begin
     n := FUDPSock.ByteCanRead;
     if n > UDPACKETSIZE then n := UDPACKETSIZE;
     FUDPSock.RecvFrom(buf, n, a, p);
     if (buf.Flag = UDPXDATAFLAG) and (n > UDPXHEADSIZE) then
       FUDPSock.SendTo(buf.Addr, buf.Port, buf.Data, n - UDPXHEADSIZE);
   end;
 end;
end;

constructor TUDPReceiver.Create(Sock: TSyncUDPSocket);
begin
 inherited Create(True);
 FUDPSock := Sock;
 FOnData := nil;
end;

procedure TUDPReceiver.Execute;
var buf: TUDPQueData;
begin
 while not Terminated do
 begin
   if FUDPSock.WaitForData(100) then with buf do
   begin
     Len := FUDPSock.ByteCanRead;
     if Len > UDPACKETSIZE then Len := UDPACKETSIZE;
     FUDPSock.RecvFrom(Data, Len, Addr, Port);
     if (FUDPSock.FLastError = 0) and Assigned(FOnData) then FOnData(Self, buf);
   end;
 end;
end;

constructor TUDPQueSender.Create(Sock: TSyncUDPSocket; BufSize: Integer);
begin
 inherited Create(True);
 FUDPSock := Sock;
 FBuffer.Header := 0;
 FBuffer.Tail := 0;
 FBuffer.IsFull := False;
 if BufSize < 4 then BufSize := 4;
 FBuffer.BufSize := BufSize;
 GetMem(FBuffer.Queue, FBuffer.BufSize * Sizeof(TUDPQueData));
 FSync := TSyncSignal.Create(True);
 FreeOnTerminate := True;
end;

destructor TUDPQueSender.Destroy;
begin
 FreeMem(FBuffer.Queue, FBuffer.BufSize * Sizeof(TUDPQueData));
 FSync.Free;
 inherited Destroy;
end;

function TUDPQueSender.AddData(Addr: Integer; Port: Word; const Header; HLen: Word;
        const Data; DLen: Word): Boolean;
var i, n: Integer;
begin
 while not FSync.IsSafe do Sleep(0);
 i := FBuffer.Tail;
 Result := not ((i = FBuffer.Header) and FBuffer.IsFull);
 if Result and ((HLen > 0) or (DLen > 0)) then
 begin
   if HLen > UDPACKETSIZE then HLen := UDPACKETSIZE;
   n := HLen + DLen;
   if n > UDPACKETSIZE then DLen := UDPACKETSIZE - HLen;
   FBuffer.Queue.Addr := Addr;
   FBuffer.Queue
.Port := Port;
   FBuffer.Queue.Len := n;
   if HLen > 0 then Move(Header, FBuffer.Queue
.Data[0], HLen);
   if DLen > 0 then Move(Data, FBuffer.Queue.Data[HLen], DLen);
   Inc(i);
   if i >= FBuffer.BufSize then i := 0;
   FBuffer.Tail := i;
   FBuffer.IsFull := i = FBuffer.Header;
 end;
 FSync.Reset;
 PostThreadMessage(ThreadID, WM_SENDDATA, 0, 0);
end;

procedure TUDPQueSender.Execute;
var i: Integer;
   ms: MSG;
begin
 while not Terminated do
 begin
   GetMessage(ms, 0, 0, 0);
   case ms.message of
     WM_SENDDATA: begin
       while (FBuffer.Header <> FBuffer.Tail) or FBuffer.IsFull do
       begin
         i := FBuffer.Header;
         with FBuffer.Queue
do
         begin
           if Len > UDPACKETSIZE then Len := UDPACKETSIZE;
           FUDPSock.SendTo(Addr, Port, Data, Len);
           Inc(i);
           if i >= FBuffer.BufSize then i := 0;
           while not FSync.IsSafe do Sleep(0);            
           FBuffer.Header := i;
           FBuffer.IsFull := False;
           FSync.Reset;
         end;
       end;
     end;
     WM_TERMINATE: Terminate;
   end;
 end;
end;

function AddrToIP(Addr: Integer): string;
var a: in_addr absolute Addr;
begin
 Result := inet_ntoa(a);
end;

function IPToAddr(const IP: string): Integer;
begin
 Result := inet_addr(PChar(IP));
end;

var
 WSAData: TWSAData;

procedure Startup;
begin
 if WSAStartup(01, WSAData) <> 0 then raise ESocketError.Create('WSAStartup');
end;

procedure Cleanup;
begin
 if WSACleanup <> 0 then raise ESocketError.Create('WSACleanup');
end;

initialization
 Startup;

finalization
 Cleanup;

end.

阅读全文(305) / 评论 / 扔小纸条 / 给kraft留言 / 文件夹: delphi

转载于:https://blog.51cto.com/525927/121286

在多线程中使用UDP相关推荐

  1. 聊聊iOS中TCP / UDP 协议

    TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于 传输层协议. UDP(User Datagram protoco ...

  2. 【Linux】多线程中使用fork()

    (最核心的东西我在下面用红色字体标出来了,理解了那块,这些东西都是就理解了!) 在本篇文章开始之前,需要大家先了解线程和进程,这位大哥讲的言简意赅:进程和线程的主要区别(总结)_kuangsongha ...

  3. java闭合数据_java多线程中线程封闭详解

    线程封闭的概念 访问共享变量时,通常要使用同步,所以避免使用同步的方法就是减少共享数据的使用,这种技术就是线程封闭. 实现线程封闭的方法 1:ad-hoc线程封闭 这是完全靠实现者控制的线程封闭,他的 ...

  4. java多线程中的join方法详解

    java多线程中的join方法详解 方法Join是干啥用的? 简单回答,同步,如何同步? 怎么实现的? 下面将逐个回答. 自从接触Java多线程,一直对Join理解不了.JDK是这样说的:join p ...

  5. linux如何关闭udp端口,如何阻止linux RHEL7中的udp端口范围(How to block udp ports range in linux RHEL7)...

    如何阻止linux RHEL7中的udp端口范围(How to block udp ports range in linux RHEL7) 需要测试使用UDP端口范围从5000到60,000英寸的应用 ...

  6. 了解多线程中的yield

    2019独角兽企业重金招聘Python工程师标准>>> 最近在学习多线程这一块,发现里面有好多让人产生误区的地方,今天我来分析下java多线程中的yield功能,希望其他朋友也可以从 ...

  7. 解决DataGridView在多线程中无法显示滚动条的问题

    解决DataGridView在多线程中无法显示滚动条的问题 参考文章: (1)解决DataGridView在多线程中无法显示滚动条的问题 (2)https://www.cnblogs.com/roph ...

  8. VMware 虚拟化编程(8) — 多线程中的 VixDiskLib

    目录 目录 前文列表 多线程注意事项 多线程中的 VixDiskLib 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/VADP 概念简析 VMware 虚拟化 ...

  9. 如何在多线程中调用winform窗体控件2——实例篇

    如何在多线程中调用winform窗体控件2--实例篇 针对之前文章<如何在多线程中调用winform窗体控件>,下面举个我项目中的实际案例,这是一个我自定义控件在异步设置焦点时的代码.在新 ...

最新文章

  1. [转]Windows CE 编程的十点忠告(by pdasky)
  2. TypeError: sequence item 0: expected str instance, int found
  3. 小学计算机教案表格式,小学信息技术教案表格数据处理.docx
  4. 吉他谱——寂寞是因为思念谁
  5. (六)关于beetlsql版本(分支)的说明
  6. Mapreduce运行过程分析(基于Hadoop2.4)——(三)
  7. Pascal调用与C调用
  8. 中国移动MM如何解决盗版问题
  9. Django 开发的个人博客源码分享
  10. Qt5.2.1 + VS2012 环境配置
  11. labview技巧——获取网络时间
  12. 解决master[remote rejected] pre-receive hook declined
  13. Lumion 9.0 动画渲染的10个技术技巧
  14. ggsurvplot的p值到底是如何计算的
  15. U盘文件全变快捷方式解决办法
  16. pyinstaller打包exe速记
  17. 100天精通Python(进阶篇)——第34天:正则表达式大总结(基础+代码实战)
  18. 1 面向对象设计模式与原则
  19. 百度SEO发包快排解密
  20. 利用小米手环记录并生成心率图

热门文章

  1. 201521123004《软件工程》个人阅读作业1
  2. 点击跳转到QQ聊天界面
  3. Python字符串笔录
  4. python和django中的常见错误
  5. System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
  6. 访问被拒绝:“microsoft.web.ui.webcontrols”的解决办法
  7. Vue.js 基础指令实例讲解(各种数据绑定、表单渲染大总结)——新手入门、高手进阶第一篇
  8. MTK-TP(电阻屏校准程序ts_lib移植)
  9. 论一个程序员的自我修养-从一张图片说起
  10. while read line的问题