gpt4 book ai didi

sockets - 10057 通过 Socket SendBuf 时出现 WSA 异常

转载 作者:行者123 更新时间:2023-12-02 05:15:51 29 4
gpt4 key购买 nike

客户:

//is called when the client tries to log in
procedure TLogin_Form.btnLoginClick(Sender: TObject);
var LoginQuery: TQuery;
begin
//If socket not open, open it
if not LoginSocket.Active then
begin
LoginSocket.Open;
end;

//create package
LoginQuery.Login := ledtName.Text;
LoginQuery.Passwort := ledtPasswort.Text;
LoginQuery.IP := LoginSocket.Socket.LocalAddress;
//send package
LoginSocket.Socket.SendBuf(LoginQuery, SizeOf(LoginQuery));
end;

服务器:

    //This procedure is executed when I click on start server button
procedure TServer_Form.btnStartStopClick(Sender: TObject);
begin
//If not open, open it
if not ServerSocket.Active then
begin
btnStartStop.Caption := 'stop server';
//Open ServerSocket
ServerSocket.Open;
end
else
begin
//If Socket open, close it, but watch for active connctions.
if ServerSocket.Socket.ActiveConnections > 0 then
begin
ShowMessage('Clients still logged in');
end
else
begin
//If no clients connected, close socket
ServerSocket.Close;
end;
end;
end;

//This procedure is called to verify weather the user is logged in and to send the verification back
procedure UserCheckExist(Login, Passwort: string);
var LoginReply: TReply;
begin
begin
//Connect to DB
DBConnect(true);
DM.AQ_LOGIN.Close;
DM.AQ_LOGIN.SQL.Clear;
//Count of BLOGINs
DM.AQ_LOGIN.SQL.Add('select count(BLOGIN) from BENU where BLOGIN = ''' + Login + ''' AND BPW = ''' + Passwort + '''');
DM.AQ_LOGIN.Open;
//LoginReply.Action tells the client then what to do with the LoginReply.Value
LoginReply.Action := 0;
//if user unique
if DM.AQ_LOGIN.Fields[0].AsInteger = 1 then
begin
//LoginReply.Value = 1 means the client is allowed to log in
LoginReply.Value := 1;
//THIS RETURNS THE WSA 10057 EXCEPTION of user is unique
Server_Form.ServerSocket.Socket.SendBuf(LoginReply, SizeOf(LoginReply));
end
else
begin
//LoginReply.Value = 0 means the client is NOT allowed to log in
LoginReply.Value := 0;

//THIS RETURNS THE WSA 10057 EXCEPTION if user is NOT unique
Server_Form.ServerSocket.Socket.SendBuf(LoginReply, SizeOf(LoginReply));
end;
//Close ADOQuery
DM.AQ_LOGIN.Close;
//Close DB Connection
DBConnect(false);
end;
end;

//Is called when something is in the socket connection
procedure TServer_Form.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var Query: TQuery;
begin
//Reads from the Socket (cant use ServerSocket.Socket.ReceiveBuf whysoever, but this is another thread)
Socket.ReceiveBuf(Query, SizeOf(Query));
case Query.Action of
//If Query.Action = 0, which means the client tries to login call UserCheckExist
0: UserCheckExist(Query.Login, Query.Passwort);
//Otherwise, getfuckedup
else ShowMessage('Query Action not defined');
end;
end;

一件奇怪的事情是我必须从客户端发送登录+密码两次。

第一次发送(客户端)时,我在服务器上得到 onClientConnect 和 onAccept 。我第二次发送(客户端)时,服务器执行代码,直到我标记的行。我收到 10057 WSA 异常。

为什么我会收到此错误?但奇怪的是,如果我在出现“套接字未打开”异常的行之前打开服务器上的套接字,我就会明白无论如何

最佳答案

由于代码中存在多个错误,您所显示的代码将无法在客户端和服务器端运行。

当 TClientSocket 设置为 ctNonBlocking 模式(我假设您正在使用该模式)时,Open() 将不会触发 OnConnect 事件,直到 btnLoginClick() 退出并且流返回到消息队列之后。在触发 OnConnect 事件之前,从套接字读取或写入数据是无效的。因此,您应该将发送代码移至 OnConnect 事件本身。您还需要考虑到 SendBuf() 可能无法在单个数据包中发送所有数据。如果 SendBuf() 返回 -1 并且 WSAGetLastError() 随后返回 WSAEWOULDBLOCK(如果未触发 OnError 事件,则该值始终为 true),则数据未完整发送。您必须在某处缓冲所有未发送的字节,然后等待 OnWrite 事件触发,然后再尝试将缓冲的字节或其他任何内容写入套接字。

对于您的服务器代码,您正尝试将出站数据写入错误的对象。您必须使用 OnRead 事件提供的 TCustomWinSocket 对象读取和写入数据。您正尝试将数据写入服务器的 TServerWinSocket 对象,该对象并不代表任何已连接客户端的有效套接字端点。您还需要查看 ReceiveBuf() 的返回值,以便处理部分传输。

尝试类似以下内容:

常见:

type
// helper class that holds buffered input/output data
SocketBuffers = class
public
constructor Create;
destructor Destroy;
Inbound: TMemoryStream;
Outbound: TMemoryStream;
end;

constructor SocketBuffers.Create;
begin
inherited;
Inbound := TMemoryStream.Create;
Outbound := TMemoryStream.Create;
end;

destructor SocketBuffers.Destroy;
begin
Inbound.Free;
Outbound.Free;
inherited;
end;

// removes processed bytes from a buffer
procedure CompactBuffer(Buffer: TMemoryStream);
begin
if Buffer.Position > 0 then
begin
// bytes have been processed, remove them from the buffer...
if Buffer.Position < Buffer.Size then
begin
// move unprocessed bytes to the front of the buffer...
Move(Pointer(Longint(Buffer.Memory)+Buffer.Position)^, Buffer.Memory^, Buffer.Size - Buffer.Position);
// reduce the buffer size just the remaining bytes...
Buffer.Size := Buffer.Size - Buffer.Position;
end else
begin
// all bytes have been processed, clear the buffer...
Buffer.Clear;
end;
end;
end;

// sends raw bytes to the specified socket, buffering any unsent bytes
function SendDataToSocket(Socket: TCustomWinSocket; Data: Pointer; DataSize: Integer; Buffer: TMemoryStream): Integer;
var
DataPtr: PByte;
NumSent: Integer;
begin
Result := 0;
DataPtr := PByte(Data);
if DataSize > 0 then
begin
if Buffer.Size = 0 then
begin
// the buffer is empty, send as many bytes as possible...
repeat
NumSent := Socket.SendBuf(DataPtr^, DataSize);
if NumSent <= 0 then Break; // error or disconnected
Inc(DataPtr, NumSent);
Dec(DataSize, NumSent);
Inc(Result, NumSent);
until DataSize = 0;
if DataSize = 0 then Exit; // nothing left to send or buffer
end;
// add unsent bytes to the end of the buffer...
Buffer.Seek(0, soFromEnd);
Buffer.WriteBuf(DataPtr^, DataSize);
Inc(Result, DataSize);
end;
end;

// sends buffered bytes to the specified socket
procedure SendBufferToSocket(Socket: TCustomWinSocket; Buffer: TMemoryStream);
var
DataPtr: PByte;
NumSent: Integer;
begin
// start at the beginning of the buffer
Buffer.Position := 0;
DataPtr := PByte(Buffer.Memory);
while Buffer.Position < Buffer.Size do
begin
NumSent := Socket.SendBuf(DataPtr^, Buffer.Size - Buffer.Position);
if NumSent <= 0 then Break; // error or disconnected
Inc(DataPtr, NumSent);
Buffer.Seek(NumSent, soFromCurrent);
end;
// remove bytes that were sent...
CompactBuffer(Buffer);
end;

// reads raw bytes from the specified socket ands buffers them
procedure ReadBufferFromSocket(Socket: TCustomWinSocket; Buffer: TMemoryStream);
var
NumRecv: Integer;
OldSize: Integer;
begin
repeat
NumRecv := Socket.ReceiveLength;
if NumRecv <= 0 then Exit; // error or no data available

// increase the size of the buffer
OldSize := Buffer.Size;
Buffer.Size := Buffer.Size + NumRecv;

// read bytes into the new memory space
NumRecv := Socket.ReceiveBuf(Pointer(Longint(Buffer.Memory)+OldSize)^, NumRecv);
if NumRecv <= 0 then
begin
// nothing read, free the unused memory
Buffer.Size := OldSize;
Exit;
end;
until False;
end;

客户:

var
Buffers: SocketBuffers = nil;

procedure TLogin_Form.FormCreate(Sender: TObject);
begin
Buffers := SocketBuffers.Create;
end;

procedure TLogin_Form.FormDestroy(Sender: TObject);
begin
LoginSocket.Close;
Buffers.Free;
end;

procedure TLogin_Form.btnLoginClick(Sender: TObject);
begin
if not LoginSocket.Active then
begin
Buffers.Inbound.Clear;
Buffers.Outbound.Clear;
LoginSocket.Open;
end;
end;

procedure TLogin_Form.LoginSocketConnect(Sender: TObject; Socket: TCustomWinSocket);
var
LoginQuery: TQuery;
begin
LoginQuery.Login := ledtName.Text;
LoginQuery.Passwort := ledtPasswort.Text;
LoginQuery.IP := LoginSocket.Socket.LocalAddress;

// send query, buffering unsent bytes if needed...
SendDataToSocket(Socket, @LoginQuery, SizeOf(LoginQuery), Buffers.Outbound);
end;

procedure TLogin_Form.LoginSocketRead(Sender: TObject; Socket: TCustomWinSocket);
var
Buffer: TmemoryStream;
Available: Integer;
Query: TQuery;
begin
Buffer := Buffers.Inbound;

// read available bytes into the buffer...
ReadBufferFromSocket(Socket, Buffer);

// process complete queries, ignore unfinished queries until later...
Buffer.Position := 0;
repeat
Available := Buffer.Size - Buffer.Position;
if Available < SizeOf(Query) then Break;
Buffer.ReadBuf(Query, SizeOf(Query));
// process query as needed ...
until False;

// remove processed bytes from the buffer...
CompactBuffer(Buffer);
end;

procedure TLogin_Form.LoginSocketWrite(Sender: TObject; Socket: TCustomWinSocket);
begin
// can send any buffered bytes now...
SendBufferToSocket(Socket, Buffers.Outbound);
end;

服务器:

procedure TServer_Form.btnStartStopClick(Sender: TObject);
begin
if not ServerSocket.Active then
begin
btnStartStop.Caption := 'stop server';
ServerSocket.Open;
end
else if ServerSocket.Socket.ActiveConnections > 0 then
begin
ShowMessage('Clients still logged in');
end
else
begin
ServerSocket.Close;
end;
end;

procedure UserCheckExist(Socket: TCustomWinSocket; Login, Password: string);
var
LoginReply: TReply;
begin
...
LoginReply.Value := ...;

// send query, buffering unsent bytes if needed...
SendDataToSocket(Socket, @LoginReply, Sizeof(LoginReply), SocketBuffers(Socket.Data).Outbound);
...
end;


procedure TServer_Form.ServerSocketClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
Socket.Data := SocketBuffers.Create;
end;

procedure TServer_Form.ServerSocketClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
SocketBuffers(Socket.Data).Free;
Socket.Data := nil;
end;

procedure TServer_Form.ServerSocketClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
Buffer: TmemoryStream;
Available: Integer;
Query: TQuery;
begin
Buffer := SocketBuffers(Socket.Data).Inbound;

// read available bytes into the buffer...
ReadBufferFromSocket(Socket, Buffer);

// process complete queries, ignore unfinished queries until later...
Buffer.Position := 0;
repeat
Available := Buffer.Size - Buffer.Position;
if Available < SizeOf(Query) then Break;
Buffer.ReadBuf(Query, SizeOf(Query));
// process query as needed ...
case Query.Action of
0: UserCheckExist(Socket, Query.Login, Query.Password);
...
end;
until False;

// remove processed bytes from the buffer...
CompactBuffer(Buffer);
end;

procedure TServer_Form.ServerSocketClientWrite(Sender: TObject; Socket: TCustomWinSocket);
begin
// can send any buffered bytes now...
SendBufferToSocket(Socket, SocketBuffers(Socket.Data).Outbound);
end;

关于sockets - 10057 通过 Socket SendBuf 时出现 WSA 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1168507/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com