Задать вопрос
CodeInside
@CodeInside

Почему не получается создать сокет?

При такой версии (ниже) создания сокета после bind вылетает ошибка 10047 (Адрес несовместим с выбранным протоколом):
DWORD WINAPI ThreadForAccept(LPVOID lpParam)
{
    SOCKET sock = socket(AF_INET,
        SOCK_STREAM,
        IPPROTO_TCP);
 
    if (sock == SOCKET_ERROR) {
        ProcessManagerServerDlg::ptr->MessageAboutError(WSAGetLastError());
        WSACleanup();
        EnableWindow(GetDlgItem(ProcessManagerServerDlg::ptr->hDialog, IDC_LAUNCH), TRUE);
        return 0;
    }
 
    int iOptval = 1;
    int res = setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
        (char *)&iOptval, sizeof(iOptval));
 
    if (res == SOCKET_ERROR) {
        ProcessManagerServerDlg::ptr->MessageAboutError(WSAGetLastError());
        WSACleanup();
        EnableWindow(GetDlgItem(ProcessManagerServerDlg::ptr->hDialog, IDC_LAUNCH), TRUE);
        return 0;
    }
 
    SOCKADDR_IN saLocal;
 
    int iFamily = AF_UNSPEC;
 
    saLocal.sin_family = (ADDRESS_FAMILY)iFamily;
    saLocal.sin_port = htons((u_short)IP_PORT);
    saLocal.sin_addr.s_addr = htonl(INADDR_ANY);
 
    res = bind(sock,
        (sockaddr*)&saLocal,
        sizeof(saLocal));
 
    if (res == SOCKET_ERROR) {
        ProcessManagerServerDlg::ptr->MessageAboutError(WSAGetLastError());
        closesocket(sock);
        WSACleanup();
        EnableWindow(GetDlgItem(ProcessManagerServerDlg::ptr->hDialog, IDC_LAUNCH), TRUE);
        return 0;
    }
 
    res = listen(sock, CONNECTION_QUEUE_SIZE);
 
    if (res == SOCKET_ERROR)    {
        ProcessManagerServerDlg::ptr->MessageAboutError(WSAGetLastError());
        closesocket(sock);
        WSACleanup();
        EnableWindow(GetDlgItem(ProcessManagerServerDlg::ptr->hDialog, IDC_LAUNCH), TRUE);
        return 0;
    }
 
    while (true) {
        int iAddrSize = sizeof(sockaddr_in);
        ClientInfo clientinfo;
        clientinfo.socket = accept(
            sock,
            (sockaddr*)&(clientinfo.addr),
            &iAddrSize);
 
        if (clientinfo.socket == INVALID_SOCKET) {
            ProcessManagerServerDlg::ptr->MessageAboutError(WSAGetLastError());
            break;
        }
 
        TCHAR str[30];
        wsprintf(str, L"The client joined");
 
        SetWindowText(ProcessManagerServerDlg::ptr->hDialog, str);
        HANDLE hThread = CreateThread(0, 0, ThreadForReceive, (LPVOID)&clientinfo, 0, 0);
        CloseHandle(hThread);
    }
    closesocket(sock);
    WSACleanup();
    EnableWindow(GetDlgItem(ProcessManagerServerDlg::ptr->hDialog, IDC_LAUNCH), true);
    return 0;
}


А вот при этой (код ниже), ошибка 10013 (Сделана попытка доступа к сокету методом, запрещенным правами доступа (даже если запускаю .exe с правами администратора).
DWORD WINAPI ThreadForAccept(LPVOID lpParam)
{
    SOCKET sock = socket(AF_INET,
        SOCK_STREAM,
        IPPROTO_TCP);
 
    if (sock == SOCKET_ERROR) {
        ProcessManagerServerDlg::ptr->MessageAboutError(WSAGetLastError());
        WSACleanup();
        EnableWindow(GetDlgItem(ProcessManagerServerDlg::ptr->hDialog, IDC_LAUNCH), TRUE);
        return 0;
    }
 
    sockaddr_in local;
    local.sin_addr.S_un.S_addr = INADDR_ANY;
    local.sin_family = AF_INET;
    local.sin_port = htons(IP_PORT);
 
    res = bind(sock,
        (sockaddr*)&local,
        sizeof(local));
 
    if (res == SOCKET_ERROR) {
        ProcessManagerServerDlg::ptr->MessageAboutError(WSAGetLastError());
        closesocket(sock);
        WSACleanup();
        EnableWindow(GetDlgItem(ProcessManagerServerDlg::ptr->hDialog, IDC_LAUNCH), TRUE);
        return 0;
    }
 
    res = listen(sock, CONNECTION_QUEUE_SIZE);
 
    if (res == SOCKET_ERROR)    {
        ProcessManagerServerDlg::ptr->MessageAboutError(WSAGetLastError());
        closesocket(sock);
        WSACleanup();
        EnableWindow(GetDlgItem(ProcessManagerServerDlg::ptr->hDialog, IDC_LAUNCH), TRUE);
        return 0;
    }
 
    while (true) {
        int iAddrSize = sizeof(sockaddr_in);
        ClientInfo clientinfo;
        clientinfo.socket = accept(
            sock,
            (sockaddr*)&(clientinfo.addr),
            &iAddrSize);
 
        if (clientinfo.socket == INVALID_SOCKET) {
            ProcessManagerServerDlg::ptr->MessageAboutError(WSAGetLastError());
            break;
        }
 
        TCHAR str[30];
        wsprintf(str, L"The client joined");
 
        SetWindowText(ProcessManagerServerDlg::ptr->hDialog, str);
        HANDLE hThread = CreateThread(0, 0, ThreadForReceive, (LPVOID)&clientinfo, 0, 0);
        CloseHandle(hThread);
    }
    closesocket(sock);
    WSACleanup();
    EnableWindow(GetDlgItem(ProcessManagerServerDlg::ptr->hDialog, IDC_LAUNCH), true);
    return 0;
}


Можете пожалуйста помочь решить эту проблему?
  • Вопрос задан
  • 737 просмотров
Подписаться 1 Оценить Комментировать
Пригласить эксперта
Ответы на вопрос 1
TrueBers
@TrueBers
Гуглю за еду
int iFamily = AF_UNSPEC;
 
saLocal.sin_family = (ADDRESS_FAMILY)iFamily;

Как вы собираетесь создать сокет с неопределённым типом? Он должен быть в вашем случае либо AF_INET, либо AF_INET6.

А насчёт WSAEACCESS вы читали MSDN? Там же даже табличка есть, с объяснениями ошибок и в каких случаях они появляются, и внизу указано:
Note A socket that is using the SO_EXCLUSIVEADDRUSE option must be shut down properly prior to closing it. Failure to do so can cause a denial of service attack if the associated service needs to restart.

Ещё советую почитать про TCP вообще. Про его конечный автомат, какие у него бывают состояния, что такое полу-закрытый сокет, что такое graceful shutdown, и т. п.

Когда вы используете SO_EXCLUSIVEADDRUSE, у вас не должно быть повисших соединений в любом из состояний. Т. е. не только ESTABLISHED, но и различных FIN-WAIT, TIME-WAIT, CLOSE-WAIT тоже быть не должно. Если вы биндитесь на один и тот же порт всегда, то использовать SO_EXCLUSIVEADDRUSE на клиентах будет очень проблематично, ибо всегда будете нарываться на полу-закрытый порт.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы