C ++ Windows无法绑定套接字

时间:2016-12-07 22:25:35

标签: c++ sockets

我使用NO-IP指向我的公共地址也转发了端口8844,但我的服务器仍无法正常工作。当我尝试" 127.0.0.1"相反主持它的工作,我无法找到错误的位置..

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar id="ejb-jar_ID" version="2.1" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd">
    <display-name>ESo-Listeners</display-name>
    <enterprise-beans>
        <message-driven id="PDBListenerBean">
            <ejb-name>PDBListener</ejb-name>
            <ejb-class>com.*.ejb.PDBSizeProfileBean</ejb-class>
            <transaction-type>Container</transaction-type>
            <message-destination-type>javax.jms.Queue</message-destination-type>
            <message-destination-link>jms/sizeProfilePDBRequestQueue</message-destination-link>


            <env-entry>
                <description></description>
                <env-entry-name>ejb/BeanFactoryPath</env-entry-name>
                <env-entry-type>java.lang.String</env-entry-type>
                <env-entry-value>context/eso-application-config.xml</env-entry-value>
            </env-entry>


            <resource-ref>
                <res-ref-name>jdbc/ESODS</res-ref-name>
                <res-type>javax.sql.DataSource</res-type>
                <res-auth>Container</res-auth>
                <res-sharing-scope>Shareable</res-sharing-scope>

            </resource-ref>

            <resource-ref>
                <res-ref-name>jdbc/ESOLOGDS</res-ref-name>
                <res-type>javax.sql.DataSource</res-type>
                <res-auth>Container</res-auth>
                <res-sharing-scope>Shareable</res-sharing-scope>

            </resource-ref>
        </message-driven>
        <message-driven id="ITSAListenerBean">
            <ejb-name>ITSAListener</ejb-name>
            <ejb-class>com.*.ejb.ITSASizeProfileBean</ejb-class>
            <transaction-type>Container</transaction-type>
            <message-destination-type>javax.jms.Queue</message-destination-type>
            <message-destination-link>jms/sizeProfileITSARequestQueue</message-destination-link>


            <env-entry>
                <description></description>
                <env-entry-name>ejb/BeanFactoryPath</env-entry-name>
                <env-entry-type>java.lang.String</env-entry-type>
                <env-entry-value>context/eso-application-config.xml</env-entry-value>
            </env-entry>


            <resource-ref>
                <res-ref-name>jdbc/ESODS</res-ref-name>
                <res-type>javax.sql.DataSource</res-type>
                <res-auth>Container</res-auth>
                <res-sharing-scope>Shareable</res-sharing-scope>

            </resource-ref>
            <resource-ref>
                <res-ref-name>jdbc/ESOLOGDS</res-ref-name>
                <res-type>javax.sql.DataSource</res-type>
                <res-auth>Container</res-auth>
                <res-sharing-scope>Shareable</res-sharing-scope>

            </resource-ref>


        </message-driven>
        <message-driven id="PIListenerBean">
            <ejb-name>PIListener</ejb-name>
            <ejb-class>com.*.ejb.PlanImportBean</ejb-class>
            <transaction-type>Container</transaction-type>
            <message-destination-type>javax.jms.Queue</message-destination-type>
            <message-destination-link>jms/planImportRequestQueue</message-destination-link>

            <env-entry>
                <description></description>
                <env-entry-name>ejb/BeanFactoryPath</env-entry-name>
                <env-entry-type>java.lang.String</env-entry-type>
                <env-entry-value>context/eso-application-config.xml</env-entry-value>
            </env-entry>    

            <resource-ref>
                <res-ref-name>jdbc/ESODS</res-ref-name>
                <res-type>javax.sql.DataSource</res-type>
                <res-auth>Container</res-auth>
                <res-sharing-scope>Shareable</res-sharing-scope>

            </resource-ref> 
            <resource-ref>
                <res-ref-name>jdbc/ESOLOGDS</res-ref-name>
                <res-type>javax.sql.DataSource</res-type>
                <res-auth>Container</res-auth>
                <res-sharing-scope>Shareable</res-sharing-scope>

            </resource-ref>
        </message-driven>
    </enterprise-beans>
    <assembly-descriptor id="AssemblyDescriptor_1287573859084">
        <message-destination>
            <message-destination-name>jms/sizeProfileITSARequestQueue</message-destination-name>
        </message-destination>
        <message-destination>
            <message-destination-name>jms/sizeProfilePDBRequestQueue</message-destination-name>
        </message-destination>
        <message-destination>
            <message-destination-name>jms/planImportRequestQueue</message-destination-name>
        </message-destination>
        <container-transaction>
            <method>
                <ejb-name>PDBListener</ejb-name>
                <method-name>onMessage</method-name>
                <method-params>
                    <method-param>javax.jms.Message</method-param>
                </method-params>
            </method>
            <method>
                <ejb-name>ITSAListener</ejb-name>
                <method-name>onMessage</method-name>
                <method-params>
                    <method-param>javax.jms.Message</method-param>
                </method-params>
            </method>
            <method>
                <ejb-name>PIListener</ejb-name>
                <method-name>onMessage</method-name>
                <method-params>
                    <method-param>javax.jms.Message</method-param>
                </method-params>
            </method>   
            <trans-attribute>Supports</trans-attribute>
        </container-transaction>
    </assembly-descriptor>

</ejb-jar>

1 个答案:

答案 0 :(得分:1)

您正在使用gethostbyname()(无错误检查)来获取您的公共IP(还有其他方法可以在不使用DNS查找的情况下获取该IP)。如果您的服务器位于NAT /路由器后面(如您的注释所暗示的那样,您必须将端口转发到服务器),那么您将绑定到错误的IP。您只能绑定到属于服务器计算机本地网络适配器的IP。在NAT环境中,这意味着绑定到已分配给服务器的专用LAN IP,而不是NAT的公共WAN IP。 NAT将从其公共WAN IP转发到服务器的专用LAN IP,然后服务器可以接受其专用LAN IP上的连接。这也允许服务器接受来自在具有相同LAN的其他计算机上运行的客户端的连接。

此外,inet_addr()需要一个点分子格式的IP地址,但gethostbyname()会返回二进制格式的IP地址。如果hostent::h_addrtype字段为AF_INETgethostbyname()无法保证返回),则hostent::h_addr_list字段包含指向in_addr结构的指针,然后您可以指定与sin.sin_addr字段一样。

绑定到INADDR_ANY会更容易,因此服务器可以接受任何本地IP上的连接,而不是绑定到任何特定的IP。

试试这个:

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nShow)
{
    WSADATA wsaData;
    int retVal;

    retVal = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (retVal != 0)
    {
        MessageBox(NULL, "Unable to initialize WinSock", "SOCKET ERROR", MB_OK);
        return SOCKET_ERROR;
    }

    /// Creating socket
    SOCKET servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (servSock == INVALID_SOCKET)
    {
        WSACleanup();
        MessageBox(NULL, "Unable to create socket", "SOCKET ERROR", MB_OK);
        return SOCKET_ERROR;
    }

    /// Filling in sockaddr_in struct 

    SOCKADDR_IN sin = {0};
    sin.sin_family = AF_INET;
    sin.sin_port = htons(8844);
    //sin.sin_addr.s_addr = inet_addr("192.16.0.1"); // whatever your LAN IP is
    sin.sin_addr.s_addr = INADDR_ANY;

    retVal = bind(servSock, (LPSOCKADDR)&sin, sizeof(sin));
    if (retVal == SOCKET_ERROR)
    {
        retVal = WSAGetLastError();
        MessageBox(NULL, "Unable to bind socket", "SOCKET ERROR", MB_OK);
        closesocket(servSock);
        WSACleanup();
        return SOCKET_ERROR;
    }

    retVal = listen(servSock, ...);
    if (retVal == SOCKET_ERROR)
    {
        retVal = WSAGetLastError();
        MessageBox(NULL, "Unable to listen on socket", "SOCKET ERROR", MB_OK);
        closesocket(servSock);
        WSACleanup();
        return SOCKET_ERROR;
    }

    ...

    closesocket(servSock);
    WSACleanup();

    return 0;
}

或者,您可以改为使用getaddrinfo(),让它告诉您要绑定的IP:

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nShow)
{
    WSADATA wsaData;
    int retVal;

    retVal = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (retVal != 0)
    {
        MessageBox(NULL, "Unable to initialize WinSock", "SOCKET ERROR", MB_OK);
        return SOCKET_ERROR;
    }

    addrinfo hints = {0};
    hints.ai_flags = AI_PASSIVE;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    addrinfo *addrs
    retVal = getaddrinfo(NULL, "8844", &hints, &addrs);
    if (retVal != 0)
    {
        MessageBox(NULL, "Unable to get addr info", "SOCKET ERROR", MB_OK);
        WSACleanup();
        return SOCKET_ERROR;
    }

    std::vector<SOCKET> servSocks;

    /// Creating sockets
    for(addrinfo *addr = addrs; addr != NULL; addr = addr->ai_next)
    { 
        SOCKET servSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
        if (servSock == INVALID_SOCKET)
            continue;

        retVal = bind(servSock, addr->ai_addr, addr->ai_addrlen);
        if (retVal == SOCKET_ERROR)
        {
            closesocket(servSock);
            continue;
        }

        retVal = listen(servSock, ...);
        if (retVal == SOCKET_ERROR)
        {
            closesocket(servSock);
            continue;
        }

        servSocks.push_back(servSock);
    }

    freeaddrinfo(addrs);

    if (servSocks.empty())
    {
        MessageBox(NULL, "Unable to prepare listening socket(s)", "SOCKET ERROR", MB_OK);
        WSACleanup();
        return SOCKET_ERROR;
    }

    ...

    std::for_each(servSocks.begin(), servSocks.end(), &::closesocket);
    WSACleanup();

    return 0;
}

无论哪种方式,您的NO-IP服务只是将静态主机名映射到NAT的当前公共IP,仅此而已。当客户端想要连接到主机名时,它首先将主机名解析为其当前IP,然后连接到该IP。它连接到您的NAT路由器,而不是直接连接到您的服务器。路由器将客户端转发到服务器绑定的专用LAN IP,然后服务器可以接受该连接。因此,请确保正确配置路由器的端口转发规则。如果这不能正常工作,您应该在ServerFault.com上询问,因为这是一个网络问题,而不是编码问题。

相关问题