Ошибка Winsock 10093: WSANOTINITIALISED
:
Успешный WSAStartup еще не выполнен.
Либо приложение не вызвало WSAStartup, либо WSAStartup завершился неудачно. Возможно, приложение обращается к сокету, которым не владеет текущая активная задача (то есть пытается использовать сокет совместно между задачами), или WSACleanup вызывался слишком много раз.
Ваш метод Network::Accept()
вызывает WSACleanup()
, когда accept()
по какой-либо причине не работает. Network::Accept()
вообще не должен этого делать. Он также не должен закрывать прослушивающий сокет. Удалите эти две строки из Network::Accept()
, а затем сделайте так, чтобы ваш основной цикл перестал вызывать Network::Accept()
, если он возвращает false, а затем при необходимости очистите свой прослушивающий сокет.
Есть и другие проблемы с вашим кодом Network::Accept()
:
accept()
возвращает SOCKET
, а не int
.
когда accept()
завершается успешно, вы вызываете getpeername()
с неправильными значениями параметров. Вы передаете прослушиваемый сокет вместо принятого клиентского сокета, и вы передаете недопустимый указатель для его параметра namelen
(вам нужно передать указатель на ваше значение caddrlen
, а не возвращаемое значение типа sizeof()
). В этом отношении звонить getpeername()
в любом случае излишне, поскольку accept()
уже дал вам тот же адрес, что и getpeername()
.
при вызове inet_ntop()
вы преобразуете поле sin_addr
адреса клиента в sockaddr*
, что неверно. Но в этом случае компилятор принимает его, так как параметр pAddr
является void*
. Вам вообще не нужен тип.
если listeningSocket
является сокетом AF_INET
(IPv4), то жесткое кодирование AF_INET
при вызове inet_ntop()
допустимо, поскольку принятый клиент всегда будет использовать адрес IPv4 (sockaddr_in
). Однако, если вы хотите/должны поддерживать IPv6 (и вы должны), вам следует проверить фактическое семейство адресов клиента, чтобы узнать, использует ли адрес sockaddr_in
или sockaddr_in6
, а затем передать параметры в inet_ntop()
соответственно.
С учетом сказанного попробуйте что-то еще вроде этого:
Если вы поддерживаете только IPv4:
bool Network::Accept() {
// declare clientAddr as sockaddr_in...
caddrlen = sizeof(clientAddr);
SOCKET ret = accept(listeningSocket, (struct sockaddr*)&clientAddr, &caddrlen);
if (ret == INVALID_SOCKET) {
myFormatMessage(WSAGetLastError());
return false;
}
//save client ip address in a string
char ip[INET_ADDRSTRLEN] = {0};
inet_ntop(AF_INET, &(clientAddr.sin_addr), ip, INET_ADDRSTRLEN);
clientIPaddr.assign(ip);
// declare connectedSocket as SOCKET...
connectedSocket = ret;
return true;
}
Если вы поддерживаете только IPv6:
bool Network::Accept() {
// declare clientAddr as sockaddr_in6...
caddrlen = sizeof(clientAddr);
SOCKET ret = accept(listeningSocket, (struct sockaddr*)&clientAddr, &caddrlen);
if (ret == INVALID_SOCKET) {
myFormatMessage(WSAGetLastError());
return false;
}
//save client ip address in a string
char ip[INET6_ADDRSTRLEN] = {0};
inet_ntop(AF_INET6, &(clientAddr.sin6_addr), ip, INET6_ADDRSTRLEN);
clientIPaddr.assign(ip);
// declare connectedSocket as SOCKET...
connectedSocket = ret;
return true;
}
Если вы поддерживаете как IPv4, так и IPv6:
bool Network::Accept() {
// declare clientAddr as SOCKADDR_STORAGE...
caddrlen = sizeof(clientAddr);
SOCKET ret = accept(listeningSocket, (struct sockaddr*)&clientAddr, &caddrlen);
if (ret == INVALID_SOCKET) {
myFormatMessage(WSAGetLastError());
return false;
}
//save client ip address in a string
char ip[INET6_ADDRSTRLEN] = {0};
switch (clientAddr.ss_family)
{
case AF_INET:
inet_ntop(AF_INET, &(((struct sockaddr_in*)&clientAddr)->sin_addr), ip, INET_ADDRSTRLEN);
break;
case AF_INET6:
inet_ntop(AF_INET6, &((struct sockaddr_in6*)&clientAddr)->sin6_addr), ip, INET6_ADDRSTRLEN);
break;
}
clientIPaddr.assign(ip);
// declare connectedSocket as SOCKET...
connectedSocket = ret;
return true;
}
person
Remy Lebeau
schedule
27.10.2016