Sockets getpeername()始终失败,错误代码为WSAENOTCONN
我正在尝试使用,以确保连接后可以获得对等信息 它失败于:Sockets getpeername()始终失败,错误代码为WSAENOTCONN,sockets,tcp,network-programming,Sockets,Tcp,Network Programming,我正在尝试使用,以确保连接后可以获得对等信息 它失败于: WSAENOTCON(10057) 插座未连接 不允许发送或接收数据的请求,因为套接字未连接,并且(使用sendto在数据报套接字上发送时)未提供地址 基本流程是: WSAStartup socket() connect() getpeerinfo() 我做错了什么 program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, Winapi.W
WSAENOTCON
(10057)
插座未连接
不允许发送或接收数据的请求,因为套接字未连接,并且(使用sendto在数据报套接字上发送时)未提供地址
基本流程是:
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($0202, {var}wsData);
hSocket := socket(AF_INET, SOCK_STREAM, 0);
nodeName := 'stackoverflow.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.
程序项目1;
{$APPTYPE控制台}
{$R*.res}
使用
System.SysUtils,
Winapi.Winsock2;
主程序;
变量
hSocket:TSocket;
wsData:TWSAData;
nodeName:字符串;
serviceName:string;
localAddressLength:基数;
本地地址:TSockAddr;
remoteAddressLength:基数;
远程地址:TSockAddr;
名称:TSockAddr;
nameLen:整数;
错误代码:整数;
bRes:布尔型;
开始
WSAStartup($0202,{var}wsData);
hSocket:=套接字(AF\u INET,SOCK\u STREAM,0);
nodeName:=“stackoverflow.com”;
服务名称:='80';
bRes:=WSAConnectByNameW(hSocket、PChar(nodeName)、PChar(serviceName),
{var}localAddressLength,{var}localAddress,
{var}remoteAddressLength,{var}remoteAddress,
零,零),;
如果不是bRes,那么
开始
错误代码:=WSAGetLastError;
RAISELASTERROR(错误代码);
结束;
//如果没有发生错误,getpeername将返回零。
//否则,将返回SOCKET_ERROR的值,
//并且可以通过调用WSAGetLastError检索特定的错误代码。
nameLen:=sizeof(名称);
错误代码:=getpeername(hSocket,{var}name,{var}nameLen);
如果错误代码为0,则
开始
错误代码:=WSAGetLastError;
RAISELASTERROR(错误代码);
结束;
结束;
开始
尝试
主要的;
除了
关于E:Exception-do
Writeln(E.ClassName,“:”,E.Message);
结束;
结束。
我们知道连接已连接,因为:
- 我们刚刚接通
- 我们没有检查插座是否连接
- 答案在WinSock文档中
当
WSAConnectByName
函数返回TRUE时,套接字s
处于已连接套接字的默认状态套接字s
在套接字上设置SO\u UPDATE\u CONNECT\u上下文之前,不会启用以前设置的属性或选项。使用该函数设置SO\u UPDATE\u CONNECT\u上下文选项
因此,当WSAConnectByNameW()
返回TRUE时,getpeername()
将使用WSAENOTCONN
失败,因为您没有调用setsockopt(So\u UPDATE\u CONNECT\u CONTEXT)
将套接字置于正确的状态。文件中对此进行了澄清:
所以,更新连接上下文
此选项与ConnectEx
、WSAConnectByList
、和WSAConnectByName
函数一起使用。此选项在建立连接后更新套接字的属性如果要在连接的套接字上使用getpeername
、getsockname
、getsockopt
、setsockopt
或shutdown
功能,则应设置此选项。
试试这个:
bRes:=WSAConnectByNameW(hSocket、PChar(nodeName)、PChar(serviceName),
{var}localAddressLength,{var}localAddress,
{var}remoteAddressLength,{var}remoteAddress,
零,零),;
如果不是bRes,那么
开始
错误代码:=WSAGetLastError;
RAISELASTERROR(错误代码);
结束;
//加上这个。。
错误代码:=setsockopt(hSocket,SOL_SOCKET,SO_UPDATE_CONNECT_CONTEXT,nil,0);
如果错误代码为0,则
开始
错误代码:=WSAGetLastError;
RAISELASTERROR(错误代码);
结束;
...
也就是说,在您的示例中不需要使用
getpeername()
,因为它返回的信息与WSAConnectByNameW()
在传递给它的RemoteAddress
参数的变量中已经返回的信息相同。连接后“看起来您的连接被重置了”,引用你的引文。我也很好奇,为什么你认为你需要peername,而你已经有了它。在我没有它的情况下(不是每个套接字都会用WSAConnectByName打开,甚至不是我连接的)。另外,MSFT论坛的人并没有尝试,只是在猜测。你刚刚连接的事实并不能证明它仍然连接。2.你做了什么“事情”来检查它是否仍然连接?在你的链接中没有提到。唯一有效的测试是成功的recv()
。3.有人猜测的事实并不意味着让他们错了。事实上,我仍然保持联系证明我仍然保持联系。这就是你引用的引文中的内容。它对你有用吗;你试过了吗?哇,接球不错。即使读了这篇文章,我也不会理解其中的含义。我以为它只是应用于套接字的WSAAsyncSelect
标志。还有其他一些例子,没有人调用WSAConnectByName
——我只知道我有一个Socket
句柄;而不是那个把它联系起来的人。如果socket通过connect
,connectEx
,WSAConnectByName
,WSAConnectByList
,通过侦听套接字连接,或者通过任何其他可能用于连接套接字的机制连接,那么您希望您的相同代码能够工作。connect()
和accept()
退出前,确保插座处于正确状态。使用ConnectEx()
、WSAConnectByList()
、WSAConnectByName()
和AcceptEx()
,必须在退出后单独更新状态。任何负责连接的人都有责任确保插座是正确的