I’m trying to find a solution to a question I posted earlier about synchronizing chat messages, and one member pointed me in the direction of the select() function. I read this section under Beej’s Network Guide and tried to write the sample given under windows. It compiles fine but when I go to test it, The program crashes and displays my error message "-Select error"
— after inputting the port number into the program. I’m uncertain of how to get this working, please advise.
server.cpp
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
using namespace std;
const int winsockver = 2;
int PORT;
int fdmax;
char buffer[80];
int main(void){
//*********************************************
fd_set master;
fd_set temp;
SOCKET newfd;
struct sockaddr_in connected_client;
//*********************************************
WSADATA wsadata;
if (WSAStartup(MAKEWORD(winsockver,0),&wsadata) == 0 ){
cout<<"-Winsock Initialized." << endl;
cout<<"Enter PORT:";
cin>> PORT;
//--------------------------------------------------------------------
struct sockaddr_in server_info;
server_info.sin_family = AF_INET;
server_info.sin_port = htons(PORT);
server_info.sin_addr.s_addr = INADDR_ANY;
SOCKET serv_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if ( serv_sock != INVALID_SOCKET){
if ( bind(serv_sock,(sockaddr*)&server_info,sizeof(server_info)) != -1 ){
char yes = '1';
if ( setsockopt(serv_sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) != SOCKET_ERROR){
cout<<"-Binding Successful." << endl;
}
}
if ( listen(serv_sock,5) != -1 ){
cout<<"-Listening for incoming connections." << endl;
}
FD_SET(serv_sock,&master);
fdmax = serv_sock; // keeping track of the largers sockfd, at this moment its serv_sock
//#########################################################
for(;;){
temp = master; // copying to temp the master set
if (select(fdmax+1,&temp,NULL,NULL,NULL) == -1 ){
cout<<"-select error." << endl;
}
//run through existing connections looking for data to read
for (int i = 0; i <= fdmax; i++){
if (FD_ISSET(i,&temp)){//we have one
if (i == serv_sock){//handle new connections
int size =sizeof(connected_client);
newfd = accept(serv_sock,(sockaddr*)&connected_client,&size);
if ( newfd == -1 ){
cout<<"-Accepted an invalid socket from newfd." << endl;
}else{//accept has returned a valid socket descriptor and we add it to the master
FD_SET(newfd,&master);
if (newfd > fdmax ){
fdmax = newfd;
}
char *connected_ip= inet_ntoa(connected_client.sin_addr);
cout<<"-Select server new connection from " << connected_ip << " " << endl;
}
}else{
//handle data from a client
int bytes_in;
bytes_in = recv(i,buffer,sizeof(buffer),0);
if ( bytes_in <= 0 ){
if (bytes_in == 0 ){
cout<<"-Connected socket " << i << ",disconnected " << endl;
}else{
cout<<"-Socket error." << endl;
}
closesocket(i);
FD_CLR(i,&master); //remove from master set.
}else{
//we get data from a client
for (int j=0; j <= fdmax; j++ ){
//send to everyone
if (FD_ISSET(j,&master)){
//except the listener and ourself
if ( (j != serv_sock) && (j != i) ){
if ( send(j,buffer,sizeof(buffer),0) == -1 ){
cout<<"-Sending error" << endl;
}
}
}
}
}
}
}
}
}
//#########################################################
}
//--------------------------------------------------------------------
}else{
cout<<"-Unable to Initialize." << endl;
}
if ( WSACleanup() != -1 ){
cout<<"-Cleanup Successful." << endl;
}
return 0;
}
- Remove From My Forums
-
Question
-
Hello,
I have an application which makes use of winsock. I/O part is handled on an other thread. And I am using blocking select method for sockets. But the point is that after 5-6 hours,my application gives 0xC00000FD exception, at the line of select function.
As far as I know, this exception occurs when there is recursion, or very large local variables. But neither of them is the case for me.
So do you have any idea why am I getting this exception? Or any ideas to discover what actually causes exception?
It is a server socket with a one client connected. So there is 2 socket in rset and 1 in wset. After selecting, I am checking all ready sockets and making required, read,write,accept. Timeout is 250 ms. Do you think can this be the problem? I don’t want this function to be blocking so it is not null. But what will be the exact difference if I use {0,0}
An important hint is:
Same code was working without any problem, when client socket wasn’t sending any data. But when I started sending some data from client to server this problem occured. I am sure that there is no problem with FD_SETs and FD_CLRs, I mean when client was not sending only 1(server) socket was in rset and 1(client) was in wset. So why it is working without problem when client doesn’t send any data, but giving stack overflow exception when client sends data?Anyway I had a look a lot of samples, but it seems that there is not a difference.
Please see local variables screenshot below(I have deleted name of executable, since it is a commercial product) http://img192.imageshack.us/img192/1948/stackoverflow.jpg
And here is the call stack: ntdll.dll!7c90df3a()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] mswsock.dll!71a53c9c()
ntdll.dll!7c90d26c()
mswsock.dll!71a55f9f()
mswsock.dll!71a55974()
ws2_32.dll!71ab314f()xyz.exe!vm_socket_select(vm_socket * hds=0x04c1fb84, int nhd=1, int masks=7) Line 230 + 0x1b bytes C
xyz.exe!ND::nd_socket::SocketThreadProc() Line 173 + 0x12 bytes C++
xyz.exe!ND::nd_socket::ThreadRoutineStarter(void * u=0x07d63f90) Line 332 C++
xyz.exe!_callthreadstartex() Line 348 + 0x6 bytes C
xyz.exe!_threadstartex(void * ptd=0x011a3ce8) Line 326 + 0x5 bytes C
kernel32.dll!7c80b713()I am waiting for any advice.
Many thanks
-
Moved by
Wednesday, February 10, 2010 6:02 AM
To get better support (From:Visual C++ General)
-
Moved by
WSAEINVAL (10022) Invalid argument.
Berkeley description: Some invalid argument was supplied (for example, specifying an invalid level to the setsockopt() function).
Microsoft C description: Invalid argument. An invalid value was given for one of the arguments to a function. For example, the value given for the origin when positioning a file pointer (by means of a call to fseek) is before the beginning of the file.
WinSock description: Similar to Berkeley & Microsoft C, the generic meaning is that an application passed invalid input parameter in a function call. The error refers to content as well as value (e.g. it may occur when a pointer to a structures is invalid or when a value in structure field is invalid). In some instances, it also refers to the current state of the socket input parameter.
Detailed descriptions (relevant to socket states):
accept(): listen() was not invoked prior to accept()
bind(): socket already bound to an address
getsockname(): socket not bound with bind()
listen(): socket not bound with bind() or already connected.
recv() & recvfrom(): socket not bound (for Dgram) or not yet connected (for Stream), or the requested length is zero (whether a length >32K
is acceptable as a non-negative value is unclear, so don’t use them).
send() & sendto(): socket not bound (for Dgram) or not yet connected (for Stream)
The v1.1 specification also has a detailed description for the connect() function which says: «socket not already bound to an address.» This text is a typo which makes no sense. Ignore it. The standard meaning for WSAEINVAL applies to connect() (invalid argument).
WinSock functions: accept(), bind(), getsockname(), ioctlsocket(), listen(), recv(), recvfrom(), select(), send(), setsockopt(), shutdown(), WSAStartup(), WSAAsyncSelect(), WSACancelAsyncRequest(), WSACancelBlockingCall, FD_CONNECT
Additional functions: Any WinSock function that takes input parameters that could be invalid (i.e. have bounds, or specific values) might return this error.
See more:
I have inherited some code that I am trying to understand and get working. I’m learning about sockets as I go. The method I am having problems with is one that calles the ‘select’ method. It fail and returns the error: WSAENOTSOCK. Could anyone possibly tell me what might be causing this. I have really struggled to anything that helps me with this.
The variable m_listeningSocket has been defined as an int and is the return value from socket:
int m_listeningSocket = socket(AF_INET, SOCK_STREAM, 0);
although I don’t understand why this return value has been set to an int as I thought it should be a SOCKET type — is this going to cause problems.
int Select( int timeout) { struct timeval timout; int ret, maxfdp1; if( timeout <= 0 ) return -1; maxfdp1 = m_listeningSocket + 1; FD_ZERO( &m_rset ); FD_SET ( m_listeningSocket, &m_rset ); FD_SET ( 0, &m_rset ); FD_ZERO( &m_wset ); FD_ZERO( &m_eset ); timout.tv_sec = timeout / 1000; timout.tv_usec = timeout % 1000; ret = ::select( maxfdp1, &m_rset, &m_wset, &m_eset, &timout ); return ret; }
‘getsockopt’ returns zero, indicating that there is no problem, and the rest of the code that sets the socket up before I call the Select method is:
int CCCD_Socket::CreateListenSock() { int retVal = -1; WSADATA wsaData; WORD wVersionRequested = MAKEWORD(1, 1); int err = WSAStartup(wVersionRequested, &wsaData); if(err != 0) { printf("WSAStartup error %ld", WSAGetLastError()); WSACleanup(); return retVal; } struct sockaddr_in channel; memset(&channel, 0, sizeof(channel)); channel.sin_family = AF_INET; channel.sin_addr.s_addr = htonl(INADDR_ANY); channel.sin_port = htons(SERVER_PORT); m_listeningSocket = socket(AF_INET, SOCK_STREAM, 0); if(m_listeningSocket == -1) { printf("socket error %ld", WSAGetLastError()); WSACleanup(); return retVal; } int on = 1; setsockopt(m_listeningSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)); int b = bind(m_listeningSocket, (struct sockaddr*)&channel, sizeof(channel)); if(b < 0) { printf("bind error %ld", WSAGetLastError()); WSACleanup(); return retVal; } int l = listen(m_listeningSocket, 10); if(l < 0) { printf("listen error %ld", WSAGetLastError()); WSACleanup(); return retVal; } else { retVal = m_listeningSocket; } return retVal; }
unit CServer;
{ Класс сервера
}
interface
uses Classes,SysUtils,WinSock,Dialogs,StdCtrls,CPredokClientServer,FGetErrorString;
// Информация о поключившемся клиенте
type
PConnection=^TConnection; // Информация о поключившемся клиенте
TConnection=record
ClientAddr:string; // Строковое представление адреса клиента
ClientSocket:TSocket; // Сокет, созданный accept для взаимодействия с клиентом
Deleted:Boolean; // Если FALSE, то соединение с клиентом утеряно
end;
type
TServer=class(TPredokClientServer)
private
FClientSocket:TSocket; // Сокет клиента
FClientSocketAddr:TSockAddr; // Адрес клиента
FConnections:TList; // Список подключившихся клиентов
FMemoLog:TMemo;
// Привязка сокета к адресу
procedure PrivyazkaKAdresu(MemoLog:TMemo);
// Создание соединения с клиентом
procedure SozdatSoedineniyeSKlientom;
// Принять сообщение
procedure PrinyatSoobchsheniye(var Connection: TConnection);
public
// Запуск сервера
procedure StartServer(IpAddres:string;Port:word;TypeProtokol,TypeSocket:char;MemoLog:TMemo);
end;
implementation
// ———- Запуск сервера —————————————————
// — IpAddres — ip-адрес
// — Port — номер порта
// — TypeProtokol — тип сокера (UDP,TCP)
// — TypeSocket — тип сокета (С — сервер, К — клиент)
// — MemoLog — Лог
procedure TServer.StartServer(IpAddres:string;Port:word;TypeProtokol,TypeSocket:char;MemoLog:TMemo);
begin
FMemoLog:=MemoLog;
// Создание сокета
CreateSocket(IpAddres,Port,TypeProtokol,TypeSocket);
// Привязка сокета к адресу
PrivyazkaKAdresu(MemoLog);
// Создание соединения с клиентом
SozdatSoedineniyeSKlientom;
end;
// ———- Привязка сокета к адресу ——————————————
procedure TServer.PrivyazkaKAdresu;
begin
// Сокет, созданный с помощью функции socket не привязан ни к какому адрему.
// Привязка осуществляется функцией bind.
// function bind(s:TSocket; var addr:TSockAddr; namelen:Integer): Integer;
// — s — дескриптор сокета, который привязывается к адресу
// — addr — адрес, к которому требуется привязать сокет
// — namelen — длина структуры, содержащей адрес
if bind(FSocket,FSocketAddr,SizeOf(TSockAddr)) = SOCKET_ERROR
then
begin
MessageDlg(‘Ошибка при привязке сокета к адресу ‘ + GetErrorString, mtError, [mbOK], 0);
Exit;
end
else FMemoLog.Lines.Append(‘Сервер успешно запущен’);
end;
// ———- Создание соединения с клиентом ————————————
procedure TServer.SozdatSoedineniyeSKlientom;
var
TimeOut:TimeVal; // Таймаут для функции select
SetSockets:TFDSet; // Множество сокетов для функции select
ClientAddrLen:Integer;
NewConnection:PConnection; // Вспомогательная переменная, использующаяся при создании нового соединения
x:word;
begin
FConnections:=TList.Create;
// Перевод сокета в режим ожидания соединения
// function listen(s:TSocket; backlog:Integer): Integer;
// — s — дескриптор сокета, который переводится в режим ожидания
// — backlog — размер очереди подключений (для сокета, находящегося в режиме
// ожидания, создаётся очередь подключений). Максимально возможный
// размер очереди
// Функция вовращает 0 в случае успешного завершения или SOCKET_ERROR в случае
// ошибки.
// Когда клиент вызывает функцию connect, и по указанному в ней адресу имеется
// сокет, находящийся в режиме ожидания подключения, то информация о клиенте
// помещается в очередь подключений этого сокета.
if listen(FSocket, SOMAXCONN)=SOCKET_ERROR
then MessageDlg(‘Невозможно установить сокет в режим прослушивания. ‘+GetErrorString,mtError,[mbOK],0);
// Устанавливаем таймаут, равный 0, чтобы select ничего не ждала, а возвращала готовность
// сокетов на момент вызова
Timeout.tv_sec:=0; // число секунд
Timeout.tv_usec:=0; // число микросекунд
// Начало цикла для подключения и общения с клиентами
repeat
// Сначала проверяем, готов ли слушающий сокет. Если он готов, это означает,
// что есть подключившийся, но не обработанный функцией accept клиент
// procedure FD_ZERO(var FDSet:TFDSet); — инициализирует множество FDSet
FD_ZERO(SetSockets);
// procedure FDSet(Socket:TSocket; var FDSet:TFDSet); — добавляет сокет Socket в множество FDSet
FD_SET(FSocket,SetSockets);
// Проверка готовности сокета
// function select(nfds:Integer; readfds,writefds,exceptfds:PFDSet; timeout:PTimeVal): LongInt;
// — nfds — оставлен только для совместимости со старыми версиями библиотеки сокетов, в новых игнорируется
// — readfds, writefds, exceptfds — указатели на множество сокетов, которые нужно проверять
// (не будут блокировать нить readfds-recv,recvfrom; writefds-send,sento;
// exceptfds — неудача попытки соединения, получения высокоуровневых данных)
// — timeout — время, которое функция будет ожидать, пока хотя бы один из сокетов не будет готов к требуемой операции
if select(0,@SetSockets,nil,nil,@Timeout)=SOCKET_ERROR
then MessageDlg(‘Ошибка при проверке готовности слушающего сокета. ‘ + GetErrorString, mtError, [mbOK], 0);
// Если функция select оставила сокет в множестве, значит, зафиксировано подключение клиента, и функция accept
// не приведёт к блокированию нити.
// procedure FD_ISSET(Socket:TSocket; FDSet:TFDSet) — определяет, входит ли Socket в множество FDSet
if FD_ISSET(FSocket,SetSockets)
then
begin
ClientAddrLen:=SizeOf(FClientSocketAddr);
// Ожидаем подключение клиента
// Извлечение из очереди соединений информации соединении и создание сокета для
// его обслуживания
// function accept(s:TSocket; addr:PSockAddr; addrlen: PInteger): TSocket;
// — s — сокет, который находится в режиме ожидания соединения
// — addr — адрес клиента, установившего соединение
// — addrlen — длина буфера, в который будет помещён адрес клиента
// В случае ошибки возвращается INVALID_SOCKET, при успешном завершении — дескриптор
// сокета, созданного библиотекой сокетов и предназначенного для обслуживания
// данного соединения. Этот сокет уже привязан к адресу и соединён с сокетом клиента,
// установившего соединение.
// Если на момент вызова функции accept очередь соединений пуста, то нить,
// вызвавшая её блокируется до тех пор, пока какой-нибудь клиент не полключиться
// к серверу.
FClientSocket:=accept(FSocket,@FClientSocketAddr,@ClientAddrLen);
if FClientSocket=INVALID_SOCKET then
begin
MessageDlg(‘Ошибка при ожидании подключения клиента: ‘ + GetErrorString, mtError, [mbOK], 0);
break;
end
else
begin
// Создаём в динамической памяти новый экземпляр TConnection и заполняем его данными, соответствующими
// подключившемуся клиенту
New(NewConnection);
NewConnection.ClientSocket:=FClientSocket;
NewConnection.ClientAddr:=Format(‘%u.%u.%u.%u:%u’, [
Ord(FClientSocketAddr.sin_addr.S_un_b.s_b1),
Ord(FClientSocketAddr.sin_addr.S_un_b.s_b2),
Ord(FClientSocketAddr.sin_addr.S_un_b.s_b3),
Ord(FClientSocketAddr.sin_addr.S_un_b.s_b4),
ntohs(FClientSocketAddr.sin_port)]);
NewConnection.Deleted:=False;
// Добавляем соединение в список
FConnections.Add(NewConnection);
FMemoLog.Lines.Append(‘Зафиксировано подключение с адреса ‘+NewConnection.ClientAddr);
end;
end;
if FConnections.Count>0
then
begin
// Теперь проверяем готовность всех сокетов подключившихся клиентов
FD_ZERO(SetSockets);
for x:=0 to FConnections.Count-1
do FD_SET(PConnection(FConnections[x])^.ClientSocket,SetSockets);
if select(0, @SetSockets, nil, nil, @Timeout) = SOCKET_ERROR
then MessageDlg(‘Ошибка при проверке готовности слушающего сокета. ‘ + GetErrorString, mtError, [mbOK], 0);
// Проверяем, какие сокеты select оставила в множестве и вызываем …
for x:=0 to FConnections.Count-1
do if FD_ISSET(PConnection(FConnections[x])^.ClientSocket,SetSockets)
then PrinyatSoobchsheniye(PConnection(FConnections[x])^);
// Проверяем отключвшихся клиентов
for x:=FConnections.Count-1 downto 0
do if PConnection(FConnections[x])^.Deleted
then
begin
closesocket(PConnection(FConnections[x])^.ClientSocket);
Dispose(PConnection(FConnections[x]));
FConnections.Delete(x);
end;
end;
Sleep(100);
until False;
for x:=FConnections.Count-1 downto 0 do
begin
closesocket(PConnection(FConnections[x])^.ClientSocket);
Dispose(PConnection(FConnections[x]));
end;
FConnections.Free;
FMemoLog.Lines.Append(‘Сервер завершил работу’);
end;
// ———- Принять сообщение ————————————————
procedure TServer.PrinyatSoobchsheniye(var Connection: TConnection);
var
Mes:string[255]; // Сообщение клиента
begin
// Если выполнение функции не дойдёт до конца, это значит, что связь
// с клиентом по тем или иным причинам потеряна. В этом случае
// поле Deleted останется равным False, и ресурсы, выделенные для
// данного клиента, будут освобождены. Если же функция выполнится
// до конца, полю Deleted будет вновь присвоено значение False,
// т.е. ресурсы не будут удалены.
Connection.Deleted:=True;
// Принять сообщение
// function recv(s:TSocket; var buf,len,flags:Integer):Integer;
// — s — сокет, который служит для передачи данных
// — buf — буфер, в котором хранятся данные для оправки
// — len — размер этих данных в байтах
// — flags — указывает некоторые дополнительные опциии, которые в большинстве
// случаев не нужны
case recv(Connection.ClientSocket,Mes,SizeOf(Mes),0) of
-1: // Ошибка при принятии
begin
MessageDlg(‘Произошла ошибка при чтении ‘+GetErrorString,mtError,[mbOK],0);
exit;
end;
0: // Клиент закрыл соединение
begin
FMemoLog.Lines.Append(‘Клиент ‘+Connection.ClientAddr+’ закрыл соединение ‘);
exit;
end
else FMemoLog.Lines.Append(Mes);
end;
// Если выполнение дошло до этого места, значит, связь с клиентом
// не потеряна, и ресурсы освобождать не надо.
Connection.Deleted := False;
end;
end.