Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets getpeername()始终失败,错误代码为WSAENOTCONN_Sockets_Tcp_Network Programming - Fatal编程技术网

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()
      ,必须在退出后单独更新状态。任何负责连接的人都有责任确保插座是正确的