Delphi ServerSocket只接收一次
我正在尝试通过clientsocket发送记录,并在serversocket上接收,一切正常,但只有在第一次发送后,我需要断开clientsocket,再次连接以再次发送 如果有人能帮我 以下是我如何接收信息的服务器端代码:Delphi ServerSocket只接收一次,delphi,record,serversocket,Delphi,Record,Serversocket,我正在尝试通过clientsocket发送记录,并在serversocket上接收,一切正常,但只有在第一次发送后,我需要断开clientsocket,再次连接以再次发送 如果有人能帮我 以下是我如何接收信息的服务器端代码: procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); var LBuffer: TBytes; LMessageBuffer: TBytes; L
procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
LBuffer: TBytes;
LMessageBuffer: TBytes;
LDataSize: Integer;
LProtocol: TProtocol;
begin
LDataSize := Socket.ReceiveLength;
if LDataSize >= szProtocol then begin
try
Socket.ReceiveBuf(LBuffer, SizeOf(LBuffer));
LProtocol := BytesToProtocol(LBuffer);
// check client command and act accordingly
case LProtocol.Command of
cmdConnect: begin
Memo1.Lines.Add(Format('[%s][%s][%s]', ['Connect', LProtocol.Sender.UserName, TimeToStr(LProtocol.Sender.ID)]));
end; // cmdConnect: begin
cmdDisconnect: begin
Memo1.Lines.Add(Format('[%s][%s][%s]', ['Disconnect', LProtocol.Sender.UserName, TimeToStr(LProtocol.Sender.ID)]));
end; // cmdDisconnect: begin
end;
finally
ClearBuffer(LBuffer);
end;
end;
end;
这里是客户端:
var
LBuffer: TBytes;
LProtocol: TProtocol;
x : Integer;
begin
InitProtocol(LProtocol);
LProtocol.Command := cmdConnect;
ClientData.UserName := Edit1.Text;
ClientData.ID := Now;
LProtocol.Sender := ClientData;
LBuffer := ProtocolToBytes(LProtocol);
try
ClientSocket1.Socket.SendBuf(LBuffer, Length(LBuffer));
finally
ClearBuffer(LBuffer);
end;
记录声明:
type
TCommand = (
cmdConnect,
cmdDisconnect,
cmdMessageBroadcast,
cmdMessagePrivate,
cmdScreenShotGet,
cmdScreenShotData);
// client information structure, you can extend this based on your needs
type
TClient = record
UserName: string[50];
ID: TDateTime;
end; // TClient = record
// size of the client information structure
const
szClient = SizeOf(TClient);
谢谢:)t字节是一个动态数组,但您将其视为一个静态数组 在客户端代码中,您没有正确发送
LBuffer
。作为一个动态数组,LBuffer
只是指向存储在内存中其他位置的数据的指针。因此,您需要取消引用LBuffer
,将正确的内存地址传递到SendBuf()
在服务器代码中,在读取字节之前,您甚至没有为LBuffer
分配任何内存。而且,与客户端一样,在将其传递到ReceiveBuf()时,需要取消对LBuffer
的引用。告诉ReceiveBuf()
要读取多少字节时,还需要使用正确的字节大小(SizeOf(TBytes)
使用的值错误)
最后,您需要注意SendBuf()
和ReceiveBuf()
的返回值,因为它们返回的字节数可能比处理请求的字节数少!因此,您应该在循环中调用SendBuf()
和ReceiveBuf()
试试这个:
var
LBuffer: TBytes;
LProtocol: TProtocol;
LBufferPtr: PByte;
LBufferLen: Integer;
LNumSent: Integer;
begin
InitProtocol(LProtocol);
LProtocol.Command := cmdConnect;
ClientData.UserName := Edit1.Text;
ClientData.ID := Now;
LProtocol.Sender := ClientData;
LBuffer := ProtocolToBytes(LProtocol);
LBufferPtr := PByte(LBuffer);
LBufferLen := Length(LBuffer);
repeat
LNumSent := ClientSocket1.Socket.SendBuf(LBufferPtr^, LBufferLen);
if LNumSent = -1 then
begin
// if ClientSocket1.ClientType is set to ctNonBlocking,
// uncomment this check ...
{
if WSAGetLastError() = WSAEWOULDBLOCK then
begin
// optionally call the Winsock select() function to wait
// until the socket can accept more data before calling
// SendBuf() again...
Continue;
end;
}
// ERROR!
ClientSocket1.Close;
Break;
end;
Inc(LBufferPtr, LNumSent);
Dec(LBufferLen, LNumSent);
until LBufferLen = 0;
end;
您没有显示什么是TProtocol
,如何定义szProtocol
,或者如何将TProtocol
序列化到字节数组或从字节数组序列化。字节数组的长度始终相同,还是长度可变?这对通过套接字发送它的方式有很大的不同。在粘贴时,我遇到了连接卡住的TIdTCPServer问题,因此我不再使用它。你有一些例子来管理和他的关系吗?我指的是一个记录,用于保存连接的客户端并在以后管理它们的客户端。在indy示例中,不需要检查ReadBytes是否小于协议,以避免ppl连接并发送奇怪的信息?@P–MBolsoni如果您在TIdTCPServer
中管理客户端时遇到问题,请发布有关该问题的新问题,并显示您的代码。但是请注意,TIdTCPServer
为您跟踪连接的客户端(在TIdTCPServer.Contexts
属性中),您不需要手动跟踪它们。至于ReadBytes()
,它会阻塞直到收到szProtocol
字节数,这与您的Socket类似。ReceiveLength
检查您的TServerSocket
代码。您有责任验证接收到的字节是否符合预期。是的,我刚刚要求使用TIdTCPServer,在SocketServer上,我检查长度是否小于协议,并执行心跳以确定连接是否正确。后来我再次尝试使用TIdTCPServer,而不是现在。我已经解决了这个问题后,张贴这个话题,但我会分析你的答案。谢谢。Remy Lebeau用你的例子说明我如何向客户发送文本协议?
procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
LBuffer: TBytes;
LDataSize: Integer;
LProtocol: TProtocol;
LBufferPtr: PByte;
LBufferLen: Integer;
LNumRecvd: Integer;
begin
LDataSize := Socket.ReceiveLength;
if LDataSize < szProtocol then Exit;
SetLength(LBuffer, szProtocol);
repeat
// since you are validating ReceiveLength beforehand, ReceiveBuf()
// *should not* return fewer bytes than requested, but it doesn't
// hurt to be careful...
LBufferPtr := PByte(LBuffer);
LBufferLen := szProtocol;
repeat
LNumRecvd := Socket.ReceiveBuf(LBufferPtr^, LBufferLen);
if LNumRecvd <= 0 then Exit;
Inc(LBufferPtr, LNumRecvd);
Dec(LBufferLen, LNumRecvd);
Dec(LDataSize, LNumRecvd);
until LBufferLen = 0;
LProtocol := BytesToProtocol(LBuffer);
// check client command and act accordingly
case LProtocol.Command of
cmdConnect: begin
Memo1.Lines.Add(Format('[%s][%s][%s]', ['Connect', LProtocol.Sender.UserName, TimeToStr(LProtocol.Sender.ID)]));
end;
cmdDisconnect: begin
Memo1.Lines.Add(Format('[%s][%s][%s]', ['Disconnect', LProtocol.Sender.UserName, TimeToStr(LProtocol.Sender.ID)]));
end;
end;
until LDataSize < szProtocol;
end;
type
PTIdBytes = ^TIdBytes;
var
LBuffer: TBytes;
LProtocol: TProtocol;
begin
InitProtocol(LProtocol);
LProtocol.Command := cmdConnect;
ClientData.UserName := Edit1.Text;
ClientData.ID := Now;
LProtocol.Sender := ClientData;
LBuffer := ProtocolToBytes(LProtocol);
// TBytes and TIdBytes are technically the same thing under the hood,
// but they are still distinct types and not assignment-compatible,
// so using a dirty hack to pass a TBytes as a TIdBytes without having
// to make a copy of the bytes...
IdTCPClient1.IOHandler.Write(PTIdBytes(@LBuffer)^);
end;
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
type
PTBytes = ^TBytes;
var
LBuffer: TIdBytes;
LProtocol: TProtocol;
// note: TIdTCPServer is a multi-threaded component, so you must
// sync with the main thread when accessing the UI...
procedure AddToMemo(const AStr: string);
begin
TThread.Synchronize(nil,
procedure
begin
Memo1.Lines.Add(AStr);
end
);
end;
begin
// ReadBytes() can allocate the buffer for you...
AContext.Connection.IOHandler.ReadBytes(LBuffer, szProtocol);
// using a similar dirty hack to pass a TIdBytes as a TBytes
// without making a copy of the bytes ...
LProtocol := BytesToProtocol(PTBytes(@LBuffer)^);
// check client command and act accordingly
case LProtocol.Command of
cmdConnect: begin
AddToMemo(Format('[%s][%s][%s]', ['Connect', LProtocol.Sender.UserName, TimeToStr(LProtocol.Sender.ID)]));
end;
cmdDisconnect: begin
AddToMemo(Format('[%s][%s][%s]', ['Disconnect', LProtocol.Sender.UserName, TimeToStr(LProtocol.Sender.ID)]));
end;
end;
end;