getpeername() 总是失败,错误代码为 WSAENOTCONN
getpeername() always fails with error code WSAENOTCONN
我正在尝试使用 getpeerinfo
来确保我可以在连接后获取对等信息。
它失败了:
WSAENOTCONN
(10057)
Socket is not connected.
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using sendto) no address was supplied.
基本流程是:
WSAStartup
socket()
connect()
getpeerinfo()
我做错了什么?
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Winapi.Winsock2;
procedure Main;
var
hSocket: TSocket;
wsData: TWSAData;
nodeName: string;
serviceName: string;
localAddressLength: Cardinal;
localAddress: TSockAddr;
remoteAddressLength: Cardinal;
remoteAddress: TSockAddr;
name: TSockAddr;
nameLen: Integer;
errorCode: Integer;
bRes: Boolean;
begin
WSAStartup(02, {var}wsData);
hSocket := socket(AF_INET, SOCK_STREAM, 0);
nodeName := 'whosebug.com';
serviceName := '80';
bRes := WSAConnectByNameW(hSocket, PChar(nodeName), PChar(serviceName),
{var}localAddressLength, {var}localAddress,
{var}remoteAddressLength, {var}remoteAddress,
nil, nil);
if not bRes then
begin
errorCode := WSAGetLastError;
RaiseLastOSError(errorCode);
end;
//If no error occurs, getpeername returns zero.
//Otherwise, a value of SOCKET_ERROR is returned,
//and a specific error code can be retrieved by calling WSAGetLastError.
nameLen := sizeof(name);
errorCode := getpeername(hSocket, {var}name, {var}nameLen);
if errorCode <> 0 then
begin
errorCode := WSAGetLastError;
RaiseLastOSError(errorCode);
end;
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
我们知道连接已连接,因为:
- 我们刚刚连接
- 我们the thing检查套接字是否已连接
红利阅读
答案在 WinSock 文档中。
When the WSAConnectByName
function returns TRUE, the socket s
is in the default state for a connected socket. The socket s
does not enable previously set properties or options until SO_UPDATE_CONNECT_CONTEXT is set on the socket. Use the setsockopt function to set the SO_UPDATE_CONNECT_CONTEXT option.
因此,当 WSAConnectByNameW()
returns 为真时,getpeername()
失败并返回 WSAENOTCONN
因为您没有调用 setsockopt(SO_UPDATE_CONNECT_CONTEXT)
将套接字置于正确的状态. SOL_SOCKET Socket Options 文档对此进行了说明:
SO_UPDATE_CONNECT_CONTEXT
This option is used with the ConnectEx
, WSAConnectByList
, and WSAConnectByName
functions. This option updates the properties of the socket after the connection is established. This option should be set if the getpeername
, getsockname
, getsockopt
, setsockopt
, or shutdown
functions are to be used on the connected socket.
试试这个:
bRes := WSAConnectByNameW(hSocket, PChar(nodeName), PChar(serviceName),
{var}localAddressLength, {var}localAddress,
{var}remoteAddressLength, {var}remoteAddress,
nil, nil);
if not bRes then
begin
errorCode := WSAGetLastError;
RaiseLastOSError(errorCode);
end;
// ADD THIS..
errorCode := setsockopt(hSocket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, nil, 0);
if errorCode <> 0 then
begin
errorCode := WSAGetLastError;
RaiseLastOSError(errorCode);
end;
...
也就是说,没有必要在您的示例中使用 getpeername()
,因为它 returns 与变量中 WSAConnectByNameW()
已经 returns 相同的信息正在传递给它的 RemoteAddress
参数。
我正在尝试使用 getpeerinfo
来确保我可以在连接后获取对等信息。
它失败了:
WSAENOTCONN
(10057)Socket is not connected.
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using sendto) no address was supplied.
基本流程是:
WSAStartup
socket()
connect()
getpeerinfo()
我做错了什么?
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Winapi.Winsock2;
procedure Main;
var
hSocket: TSocket;
wsData: TWSAData;
nodeName: string;
serviceName: string;
localAddressLength: Cardinal;
localAddress: TSockAddr;
remoteAddressLength: Cardinal;
remoteAddress: TSockAddr;
name: TSockAddr;
nameLen: Integer;
errorCode: Integer;
bRes: Boolean;
begin
WSAStartup(02, {var}wsData);
hSocket := socket(AF_INET, SOCK_STREAM, 0);
nodeName := 'whosebug.com';
serviceName := '80';
bRes := WSAConnectByNameW(hSocket, PChar(nodeName), PChar(serviceName),
{var}localAddressLength, {var}localAddress,
{var}remoteAddressLength, {var}remoteAddress,
nil, nil);
if not bRes then
begin
errorCode := WSAGetLastError;
RaiseLastOSError(errorCode);
end;
//If no error occurs, getpeername returns zero.
//Otherwise, a value of SOCKET_ERROR is returned,
//and a specific error code can be retrieved by calling WSAGetLastError.
nameLen := sizeof(name);
errorCode := getpeername(hSocket, {var}name, {var}nameLen);
if errorCode <> 0 then
begin
errorCode := WSAGetLastError;
RaiseLastOSError(errorCode);
end;
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
我们知道连接已连接,因为:
- 我们刚刚连接
- 我们the thing检查套接字是否已连接
红利阅读
答案在 WinSock 文档中。
When the
WSAConnectByName
function returns TRUE, the sockets
is in the default state for a connected socket. The sockets
does not enable previously set properties or options until SO_UPDATE_CONNECT_CONTEXT is set on the socket. Use the setsockopt function to set the SO_UPDATE_CONNECT_CONTEXT option.
因此,当 WSAConnectByNameW()
returns 为真时,getpeername()
失败并返回 WSAENOTCONN
因为您没有调用 setsockopt(SO_UPDATE_CONNECT_CONTEXT)
将套接字置于正确的状态. SOL_SOCKET Socket Options 文档对此进行了说明:
SO_UPDATE_CONNECT_CONTEXT
This option is used with the
ConnectEx
,WSAConnectByList
, andWSAConnectByName
functions. This option updates the properties of the socket after the connection is established. This option should be set if thegetpeername
,getsockname
,getsockopt
,setsockopt
, orshutdown
functions are to be used on the connected socket.
试试这个:
bRes := WSAConnectByNameW(hSocket, PChar(nodeName), PChar(serviceName),
{var}localAddressLength, {var}localAddress,
{var}remoteAddressLength, {var}remoteAddress,
nil, nil);
if not bRes then
begin
errorCode := WSAGetLastError;
RaiseLastOSError(errorCode);
end;
// ADD THIS..
errorCode := setsockopt(hSocket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, nil, 0);
if errorCode <> 0 then
begin
errorCode := WSAGetLastError;
RaiseLastOSError(errorCode);
end;
...
也就是说,没有必要在您的示例中使用 getpeername()
,因为它 returns 与变量中 WSAConnectByNameW()
已经 returns 相同的信息正在传递给它的 RemoteAddress
参数。