129分问编写多线程的网络程序需要注意什么,最好有代码例子!

Linux2001 2002-10-14 08:20:30
加精
在Windows下开发多线程的Winsock程序应该注意什么,比如:当网络速度比较慢的时候,发送出去的字节数和实际发送的不符怎么处理,接受也是一样的道理,这里一定是Winsock API而不是delphi下的TClientSocket和TServerSocket!最好有例子或书籍说明一下,顺便大家推荐一下,学习Winsock API函数的书吧
...全文
185 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
Linux2001 2002-10-22
  • 打赏
  • 举报
回复
谢谢各位,我回去看看,搞定立刻结贴
Linux2001 2002-10-21
  • 打赏
  • 举报
回复
我看了很多讲解Delphi下多线程的书,没有哪一本讲的比较好,都是些无聊的东西,没有网络方面多线程应用的实例,我只有先看一下楼上大哥的代码再说了
naughtyboy 2002-10-21
  • 打赏
  • 举报
回复
我以前位朋友做过一个多线程扫描程序
挺麻烦的
既要注意套接字的关闭CloseSocket,还要注意到线程的结束YourThread.terminate
当时我用的是TThread类来实现的
把这两个要注意到的问题都封装在自己的方法里面MyScanEv
copy_paste 2002-10-21
  • 打赏
  • 举报
回复
这是偶前段写的测试程序,我现正在封装(超麻烦),你看看吧。
就是一个简单应答的例子,因为是写测试,所以我按自已能看够的写,也没写注解,先看看吧。
copy_paste 2002-10-21
  • 打赏
  • 举报
回复
////////////////////
客户端
////////////////////
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ScktComp;

const
WM_PROGRESS = WM_USER + $100;

type
TForm1 = class(TForm)
ClientSocket1: TClientSocket;
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
FThread: TThread;
FSendCount: Integer;
procedure SendProgress(var msg: TMessage); message WM_PROGRESS;
procedure ThreadTerminate(Sender: TObject);
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses WinSock, Unit3;
{$R *.dfm}

type
TSendThread = class(TThread)
private
FFileName: string;
FSocket: TCustomWinSocket;
procedure HandleException;
protected
procedure Execute; override;
public
constructor Create(ASocket: TCustomWinSocket; AFileName: string);
function Send(var Buffer; Count: Integer): Integer;
end;

{ TSendThread }

constructor TSendThread.Create;
begin
FSocket := ASocket;
FFileName := AFileName;
FreeOnTerminate := True;
inherited Create(False);
end;

procedure TSendThread.HandleException;
var
E: Exception;
begin
E := Exception(ExceptObject);
PostMessage(Form1.Handle, WM_PROGRESS, 3, Integer(PChar(E.Message)));
end;

procedure TSendThread.Execute;

procedure Check(Value: Boolean);
begin
if Value then
raise ESocketError.Create('Socket send error');
end;

var
P, Buffer: Pointer;
hFile: THandle;
FileInfo: TFileBlock;
RetVal, SendVal, Count, StartPos, IntSize: Integer;
begin
FillChar(FileInfo, SizeOf(FileInfo), 0);
hFile := FileOpen(FFileName, fmOpenRead);
FFileName := ExtractFileName(FFileName);
Move(FFileName[1], FileInfo.FileName, Length(FFileName));
try
PostMessage(Form1.Handle, WM_PROGRESS, 1, 0);
try
FileInfo.FileSize := FileSeek(hFile, 0, Ord(soEnd));
StartPos := Send(FileInfo, SizeOf(FileInfo));
PostMessage(Form1.Handle, WM_PROGRESS, 0, StartPos);
Dec(FileInfo.FileSize, StartPos);
FileSeek(hFile, StartPos, Ord(soBeginning));
PostMessage(Form1.Handle, WM_PROGRESS, 0, StartPos);
IntSize := SizeOf(Integer);
{ 每次传输的字节数是 Count + IntSize
Count是文件字节数,IntSize是保存了传输字节,给另一端所使用 }
Count := 10240 - IntSize;
{ Buffer前四个字节保存Data Buffer Count(Integer), 后面字节保存DataBuffer }
GetMem(Buffer, Count + IntSize);
P := Pointer(Integer(Buffer) + IntSize);
try
while not Terminated and (FSocket.SocketHandle <> INVALID_SOCKET) and
(FileInfo.FileSize > 0) do
begin
{ 这里RetVal是文件读出的字节数,发送到服务端要真正存储到文件的字节数
所以发送完成后,要检查服务端是否接收到RetVal这么多个字节,否则视为
一次传输失败。}
RetVal := FileRead(hFile, P^, Count);
if RetVal > 0 then
begin
PInteger(Buffer)^ := RetVal;
{ Send之后等待服务接收完,服务端并发送已接收的字节数作为检验手段 }
SendVal := Send(Buffer^, RetVal + IntSize);
Check(SendVal <> RetVal);
Dec(FileInfo.FileSize, RetVal);
PostMessage(Form1.Handle, WM_PROGRESS, 0, RetVal);
end;
end;
FSocket.Close;
PostMessage(Form1.Handle, WM_PROGRESS, 2, 0);
finally
FreeMem(Buffer);
end;
except
FSocket.Close;
HandleException;
end;
finally
FileClose(hFile);
end;
end;

function TSendThread.Send(var Buffer; Count: Integer): Integer;
var
FDSet: TFDSet;
TimeVal: TTimeVal;
RetVal: Integer;
begin
if FSocket.SocketHandle <> INVALID_SOCKET then
begin
Result := FSocket.SendBuf(Buffer, Count);
if Result <> Count then
raise ESocketError.Create('Socket send error.');
Result := -1;
FD_ZERO(FDSet);
FD_SET(FSocket.SocketHandle, FDSet);
TimeVal.tv_sec := 10;
TimeVal.tv_usec := 0;
RetVal := select(0, @FDSet, nil, nil, @TimeVal);
if RetVal > 0 then
begin
RetVal := FSocket.ReceiveBuf(Result, SizeOf(Result));
if RetVal <> SizeOf(Result) then
raise ESocketError.Create('Socket read error.');
end;
end
else
raise ESocketError.Create('Socket invalid');
end;

{ TForm1 }

procedure TForm1.SendProgress;
begin
case msg.WParam of
0:
begin
Inc(FSendCount, msg.LParam);
Caption := FormatFloat('###,###,###.##', FSendCount);
end;
1: FSendCount := 0;
2: Caption := 'File send over.';
3: Caption := 'Error: ' + PChar(msg.LParam);
end;
end;

procedure TForm1.ThreadTerminate(Sender: TObject);
begin
FThread := nil;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(FThread) then
begin
ClientSocket1.Close;
Sleep(10);
ClientSocket1.Host := Edit1.Text;
ClientSocket1.ClientType := ctBlocking;
ClientSocket1.Open;
if not FileExists(Edit2.Text) then
raise Exception.CreateFmt('File: %s not exists', [Edit2.Text]);
FThread := TSendThread.Create(ClientSocket1.Socket, Edit2.Text);
FThread.OnTerminate := ThreadTerminate;
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
if Assigned(FThread) then
FThread.Terminate;
end;

end.


//unit1.dfm
object Form1: TForm1
Left = 197
Top = 143
Width = 404
Height = 176
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 72
Top = 112
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object Edit1: TEdit
Left = 72
Top = 48
Width = 233
Height = 21
TabOrder = 1
Text = '192.168.1.16'
end
object Edit2: TEdit
Left = 72
Top = 80
Width = 233
Height = 21
TabOrder = 2
Text = 'c:\temp\a.rar'
end
object Button2: TButton
Left = 208
Top = 112
Width = 75
Height = 25
Caption = 'Stop Send'
TabOrder = 3
OnClick = Button2Click
end
object ClientSocket1: TClientSocket
Active = False
ClientType = ctBlocking
Port = 211
Left = 176
Top = 112
end
end
copy_paste 2002-10-21
  • 打赏
  • 举报
回复
//服务端
//unit2.pas
unit Unit2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, StdCtrls;

const
WM_PROGRESS = WM_USER + $100;

type
TForm2 = class(TForm)
ServerSocket1: TServerSocket;
Memo1: TMemo;
procedure ServerSocket1GetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
procedure FormCreate(Sender: TObject);
private
FSocketEvent: TSocketEventEvent;
procedure Progress(var msg: TMessage); message WM_PROGRESS;
procedure SocketEvent(Sender: TObject; Socket: TCustomWinSocket;
SocketEvent: TSocketEvent);
end;

var
Form2: TForm2;

implementation

uses WinSock;//, Unit3;

{$R *.dfm}
type
TClientThread = class(TServerClientThread)
protected
procedure HandleException; override;
procedure ClientExecute; override;
end;

{ TClientThread }
procedure TClientThread.HandleException;
var
E: Exception;
begin
E := Exception(ExceptObject);
if not Assigned(E) or (E is EAbort) then Exit;
if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
PostMessage(Form2.Handle, WM_PROGRESS, 3, Integer(PChar(E.Message)));
end;

type
TFileBlock = packed record
FileName: array [0..100] of Char;
FileSize: Integer;
CRC32: LongWord; // reserved
end;
procedure TClientThread.ClientExecute;

procedure Check(Value: Boolean; msg: string);
begin
if Value then raise Exception.Create(msg);
end;

function WaitForData(Timeout: Integer = 30): Boolean;
var
FDSet: TFDSet;
TimeVal: TTimeVal;
begin
TimeVal.tv_sec := Timeout;
TimeVal.tv_usec := 1;
FD_ZERO(FDSet);
FD_SET(ClientSocket.SocketHandle, FDSet);
Result := select(0, @FDSet, nil, nil, @TimeVal) > 0;
end;

function ReceiveBuf(var Buffer; Count: Integer): Integer;
begin
Result := -1;
if not WaitForData then Exit;
Result := ClientSocket.ReceiveBuf(Buffer, Count);
end;

function SendBuf(var Buffer; Count: Integer): Integer;
begin
Result := ClientSocket.SendBuf(Buffer, Count)
end;

var
hFile: THandle;
Buffer: Pointer;
FileName: string;
FileInfo: TFileBlock;
Size, BufSize, RetVal, Count, RecvCount: Integer;
begin
BufSize := 10240 ;
FileName := Format('host: %s begin send file', [ClientSocket.RemoteAddress]);
PostMessage(Form2.Handle, WM_PROGRESS, 0, Integer(PChar(FileName)));
try
RetVal := SizeOf(FileInfo);
Check(ReceiveBuf(FileInfo, RetVal) <> RetVal, 'Socket read error');
FileName := ExtractFilePath(ParamStr(0)) + 'File\' + FileInfo.FileName;
hFile := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
try
Size := FileSeek(hFile, 0, Ord(soEnd));
Check(SendBuf(Size, SizeOf(Size)) <> SizeOf(Size), 'Socket send error');
Dec(FileInfo.FileSize, Size);
GetMem(Buffer, BufSize);
try
while ClientSocket.Connected and (FileInfo.FileSize > 0) do
begin
RecvCount := 0;
if not WaitForData then break;
RetVal := ClientSocket.ReceiveBuf(Count, SizeOf(Count));
if RetVal = 0 then break;
Check(RetVal <> SizeOf(Count), 'Socket read error');
RetVal := ClientSocket.ReceiveBuf(Buffer^, Count);
while (RetVal > 0) do
begin
Check(FileWrite(hFile, Buffer^, RetVal) <> RetVal, 'File write error');
Dec(FileInfo.FileSize, RetVal);
Inc(RecvCount, RetVal);
if RecvCount >= Count then break;
RetVal := ClientSocket.ReceiveBuf(Buffer^, Count - RecvCount);
end;
if RecvCount > 0 then
begin
RetVal := SendBuf(RecvCount, SizeOf(RecvCount));
Check((RetVal = 0) or (RetVal <> SizeOf(Integer)),
Format('Socket send error: RecvCount: %d', [RecvCount]));
end;
end;
PostMessage(Form2.Handle, WM_PROGRESS, 2, 0);
finally
ClientSocket.Close;
FreeMem(Buffer);
end;
finally
FileClose(hFile);
end;
except
ClientSocket.Close;
HandleException;
end;
end;

{ TForm2 }

procedure TForm2.Progress;
begin
case msg.WParam of
0: Memo1.Lines.Add('Message: ' + PChar(msg.LParam));
2: Memo1.Lines.Add('recv over');
3: Memo1.Lines.Add('Error: ' + PChar(msg.LParam));
end;
end;

procedure TForm2.ServerSocket1GetThread;
begin
SocketThread := TClientThread.Create(False, ClientSocket);
end;

procedure TForm2.SocketEvent;
var
Reuse: Integer;
begin
if Assigned(FSocketEvent) then
FSocketEvent(Sender, Socket, SocketEvent);
if SocketEvent = seLookUp then
begin
Reuse := 1;
if Socket.SocketHandle <> INVALID_SOCKET then
setsockopt(Socket.SocketHandle, SOL_SOCKET, SO_REUSEADDR,
PChar(@Reuse), SizeOf(Reuse));
end;
end;

procedure TForm2.FormCreate;
var
Dir: string;
begin
FSocketEvent := ServerSocket1.Socket.OnSocketEvent;
ServerSocket1.Socket.OnSocketEvent := SocketEvent;
ServerSocket1.Active := True;
Dir := ExtractFilePath(ParamStr(0)) + 'File\';
if not DirectoryExists(Dir) then CreateDir(Dir);
end;

end.

//unit2.dfm
object Form2: TForm2
Left = 192
Top = 106
Width = 378
Height = 237
Caption = 'Form2'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Memo1: TMemo
Left = 8
Top = 8
Width = 353
Height = 193
Lines.Strings = (
'Memo1')
ScrollBars = ssBoth
TabOrder = 0
end
object ServerSocket1: TServerSocket
Active = False
Port = 211
ServerType = stThreadBlocking
OnGetThread = ServerSocket1GetThread
Left = 208
Top = 120
end
end
wisenowa 2002-10-21
  • 打赏
  • 举报
回复
就楼主的问题而言
这些应该与线程无关的,解释如下
发送端:如果是Delphi的控件,直接使用SendStream或SendBuf来发送就行了,至于怎么全部发送,你就无需管它了,如果直接用API那也可以用SendBuf来做,道理一样。
接受端:这里是重点,如果使用Delphi的控件,则它的OnRead事件只要有数据可以接受就会不停的执行,但是怎么才知道我接受完数据了呢?那就可你的编程技巧了,网上有很多关于这方面的东西。如果是直接用API也是一样的,只不过是一直在处理WM_XXXXXX的FD_READ事件而已。
Linux2001 2002-10-21
  • 打赏
  • 举报
回复
现在我的程序在没有多线程的时候可以通过,但是移植到多线程中调试时候会死机,运行时候什么事情都不会发生,为什么
copy_paste 2002-10-21
  • 打赏
  • 举报
回复
以前CSDN没有三次回复就不能再回复的,不过我记得好像是一个家伙十几分钟回复了150多次,使自己的参与分骤增(以前参与分可兑可用分),所以限了这功能,后面又限制了表达的文章不能超过XXX, faint,写个程序哪个是几行可以完的。
copy_paste 2002-10-21
  • 打赏
  • 举报
回复
goon
建议老兄把一些常用的功能写成函数。。。不然上面看起来很累人。
ZhuJunfeng 2002-10-21
  • 打赏
  • 举报
回复

//receive welcome info
j:=0;
while Head<>'220' do
begin
if j<100 then
begin
FillChar(recvbuf,sizeof(recvbuf),0);
if Recv(hSocket,recvbuf,SizeOf(recvbuf),0)=SOCKET_ERROR then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Receive Welcome Infomation error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
recvbuf[StrLen(recvbuf)-2]:=#0;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',RECV:'+recvbuf+'"',Now));
StrLCopy(Head,recvbuf,3);
Inc(j);
end
else
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Receive Welcome Infomation Head error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
end;
//send "helo" to host

FillChar(sendbuf,sizeof(sendbuf),0);
StrCopy(sendbuf,PChar('HELO '+SmtpHostIp[SmtpId]+#13#10));
if Send(hSocket,sendbuf,StrLen(sendbuf),0)=SOCKET_ERROR then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Send HELO error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
sendbuf[StrLen(sendbuf)-2]:=#0;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',SEND:'+sendbuf+'"',Now));
FillChar(recvbuf,sizeof(recvbuf),0);
if Recv(hSocket,recvbuf,SizeOf(recvbuf),0)=SOCKET_ERROR then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Receive HELO Reply error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
recvbuf[StrLen(recvbuf)-2]:=#0;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',RECV:'+recvbuf+'"',Now));
StrLCopy(Head,recvbuf,3);
if Head<>'250' then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Receive HELO Reply Head error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
ZhuJunfeng 2002-10-21
  • 打赏
  • 举报
回复

function SEmailThrd(p:Pointer):LongInt;stdcall;
var
MyWSA: WSAData;
SIN: TSockAddr;
hSocket: TSocket;
sendbuf:array[0..1023] of char;
recvbuf:array[0..127] of char;
Head:array[0..3] of char;
j:integer;
RecverName:String;
SmtpId:integer;
PrtStr:String;
LogStr:String;
begin
result:=0;
SmtpId:=TParam(p^).TrdId mod SmtpCount;
if SmtpId=0 then SmtpId:=SmtpCount;
FillChar(Head,sizeof(Head),0);
//initial socket

If WSAStartup(MAKEWORD(2,2), MyWSA) <> 0 Then
Begin
WSACleanup;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',WSAStartup error"',Now));
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',End Thread"',Now));
Dec(PrcsThrdCount);
Exit;
end;
hSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
If hSocket = INVALID_SOCKET Then
Begin
WSACleanup;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Create Socket error"',Now));
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',End Thread"',Now));
Dec(PrcsThrdCount);
Exit;
End;

SIN.sin_family := AF_INET;
SIN.sin_port := htons(25);
SIN.sin_addr.S_addr := inet_addr(PChar(SmtpHostIp[SmtpId]));
If connect(hSocket, SIN, SizeOf(SIN)) = SOCKET_ERROR Then
Begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Connect Host error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
if SetSockOpt(hSocket,SOL_SOCKET,SO_RCVTIMEO,PChar(@TimeOut),SizeOf(TimeOut))=SOCKET_ERROR then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Set Receive TimeOut error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
if SetSockOpt(hSocket,SOL_SOCKET,SO_SNDTIMEO,PChar(@TimeOut),SizeOf(TimeOut))=SOCKET_ERROR then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Set Send TimeOut error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
ZhuJunfeng 2002-10-21
  • 打赏
  • 举报
回复
真正的多线程,api的socket程序
(我群发邮件的时候用的)

program SEmail;
{$APPTYPE CONSOLE}

uses
SysUtils,Winsock,Windows,IniFiles;

type
TParam=record
TrdId:integer;
end;

var
hThread:Thandle;
ThreadID:DWord;
a:char;
f:TextFile;
Conf:TIniFile;
AddrList:String;
i:integer;
ThrdCount:integer;
SmtpHostIp:array[1..64] of String;
SenderAddress:array[1..64] of String;
RecverSuffix:array[1..64] of String;
MailBody:String;
PMailBody:PChar;
RcptCount:array[1..64] of integer;
fEmail:TextFile;
Email:String;
Line:String;
AddrType:integer;
SmtpCount:integer;
k:integer;
Param:^TParam;
PrcsThrdCount:integer;
TimeOut:integer;
LogFile:TextFile;
SuccFile:TextFile;
FailFile:TextFile;
RepeatCount:integer;


procedure CallExit(s:TSocket;id:integer);
begin
CloseSocket(s);
WSACleanup;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(id)+',End Thread"',Now));
Dec(PrcsThrdCount);
end;
zhxzhx 2002-10-18
  • 打赏
  • 举报
回复
顶一下
smhpnuaa 2002-10-17
  • 打赏
  • 举报
回复
TCP/ip协议能保证数据的完整性,udp就不行了!
hehou 2002-10-17
  • 打赏
  • 举报
回复
可能有帮助
http://expert.csdn.net/Expert/topic/1010/1010355.xml?temp=6.318301E-02
hehou 2002-10-17
  • 打赏
  • 举报
回复
多线程应该写在
服:bind-- listen-- (accept)
客:(connect)
说清楚一点就是:服务器开始监听后,让他一直处于一个等待状态。客户端产生一个连接线程后。服务器开始连接线程。就产生一个一对一的线程。其中WINSOCKET API中有一个重要指令来防止阻塞的。我现在在外地,不方便查看。自己可以找找TCP/IP网络开发一书看一看
hehou 2002-10-17
  • 打赏
  • 举报
回复
有同感,我也在学SOCKET API学得不怎么好,但有问题可以研究研究。
我的QQ:53880410
有关书可以看一下,TCP/IP网络开发等。
copy_paste(木石三) 的功底不错。

TO copy_paste(木石三)
copy_paste(木石三) 的QQ能不能给我们呢?
大健 2002-10-16
  • 打赏
  • 举报
回复
gz
Linux2001 2002-10-16
  • 打赏
  • 举报
回复
多线程应该怎么写代码,意思就是把什么部分的代码写在多线程中
加载更多回复(15)
源码链接: https://pan.quark.cn/s/8ddf8a1c92f9 **libcurl用于获取大型文件**libcurl作为一个开源的C语言库,提供了一系列的API来处理与URL相关的任务,涵盖了HTTP、FTP、SMTP等多种网络协议的应用。在执行大型文件的下载操作时,libcurl展现出卓越的性能表现和高度的灵活性,能够高效地管理大文件传输过程,有效预防内存溢出及其他潜在问题。**libcurl的基础操作**libcurl的基础应用包括以下几个环节:1. **初始化**:需要借助`curl_global_init()`函数来启动libcurl的工作环境。2. **建立会话句柄**:通过`curl_easy_init()`函数创建一个会话句柄,该句柄将用于后续所有的操作流程。3. **配置选项**:运用`curl_easy_setopt()`函数来设定多种参数,例如目标URL、超时时间、重试次数以及数据写入的回调函数等。4. **执行请求**:调用`curl_easy_perform()`函数来实施下载操作。5. **释放资源**:使用`curl_easy_cleanup()`函数来释放已经占用的资源。**获取大型文件时的重要设置**1. **数据写入回调函数**:在处理大型文件下载时,通常不希望一次性将整个文件载入内存。可以配置`CURLOPT_WRITEFUNCTION`选项,指定一个回调函数来处理接收到的数据片段,这样libcurl在接收到数据时会调用该函数,使得我们可以按需将数据写入文件或缓冲区。2. **缓冲策略**:可以设定缓冲区的大小(比如,通过`CURLOPT_BUFFERSIZE`),来控制每次接收数据的数量,从而优化内存...
内容概要:本文档整合了《鬼谷子·决篇》与《三略·审权变第三》《差德行第四》三大古代智慧典籍,构建了一套“决策+形势+用人”三位一体的领导力提升体系。通过28天三合实战路径、三维诊断工具、9个实用模板及独特的“身体锚点”仪式,系统解决管理者在决策犹豫、形势误判、人岗错配等方面的痛点。全文涵盖理论溯源、方法论拆解(如三步决策法、审权变四步法、差德行四步法)、历史案例对照(范蠡 vs 项羽)以及跨资源联动建议,形成从认知到实践的完整闭环。; 适合人群:中基层管理者、创业者、职场进阶者,尤其是面临决策困境、环境适应困难或团队用人问题的人群;具备一定管理经验或自我提升意识的个体亦可受益。; 使用场景及目标:① 提升重大事项的决策质量,避免反复纠结与事后后悔;② 增强对外部环境变化的敏感度与应对能力,实现灵活调整;③ 科学评估人才德才素质,实现人岗精准匹配,减少用人失误;④ 构建个人化的决策-应变-用人标准化流程(SOP)。; 阅读建议:建议按照28天路径逐步实践,结合自测表定位短板,优先突破薄弱模块;配套工具模板需实际填写使用,配合身体锚点仪式强化行为记忆;可与“诸葛亮决策术”“立将威信术”等单品联动,全面提升领导力体系。

1,594

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧