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

Linux2001 2002-10-14 08:20:30
加精
在Windows下开发多线程的Winsock程序应该注意什么,比如:当网络速度比较慢的时候,发送出去的字节数和实际发送的不符怎么处理,接受也是一样的道理,这里一定是Winsock API而不是delphi下的TClientSocket和TServerSocket!最好有例子或书籍说明一下,顺便大家推荐一下,学习Winsock API函数的书吧
...全文
141 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)

1,593

社区成员

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

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