Thread View: borland.public.cppbuilder.internet.socket
2 messages
2 total messages
Started by marko.suonpera
Sun, 12 Feb 2006 10:12
Too many calls to OnRead
Author: marko.suonpera
Date: Sun, 12 Feb 2006 10:12
Date: Sun, 12 Feb 2006 10:12
310 lines
9192 bytes
9192 bytes
So what's wrong with this code? I create the class Tcpmessager to
handle sending and receiving standard library vectors from another
machine. Either machine could be either server or client.
So when I give std::vector<double> with 15 elements as input to
WriteVector, everything works fine if I have the debugger on in the
receiving machine. If it is not on, I am more likely to get crap.
However, when ReadVector() has finished, OnRead() or OnClientRead()
immediately fire again. If the receiving machine is the server, nothing
gets read here. Then in Application->ProcessMessages() OnRead is called
again and I get a lot of nested calls to ReadVector (7-8 calls
alltogether). If the receiving machine is the server, nothing gets
read, so it is no problem. But if it is the client, sometimes a very
big number, or zero, is read as the vector size (s) on the additional
calls to OnRead and this produces errors.
Then again WriteVector always succeeds (returns true).
So I use the nonblocking mode. When I turned to blocking, the OnRead
events are never called.
I'd like the program to be able to handle vectors of at least 100000
elements long.
//---------------------------------------------------------------------------
#ifndef tcpmessagerH
#define tcpmessagerH
//---------------------------------------------------------------------------
#include <ScktComp.hpp>
#include <vector>
using std::vector;
class Tcpmessager
{
private:
TClientSocket *ClientSocket;
TServerSocket *ServerSocket;
vector<double> v;
public:
Tcpmessager(TComponent* owner);
~Tcpmessager(void);
bool vectorwasread;
AnsiString currenthost;
void FileListen(void);
void FileConnect(AnsiString _host);
void FileDisconnect(void);
bool SendData(TCustomWinSocket *Socket, void *Buffer, int BufSize);
bool ReadData(TCustomWinSocket *Socket, void *Buffer, int BufSize);
bool ReadVector(TCustomWinSocket *Socket);
bool WriteVector(const vector<double> &u);
void GetVector(vector<double> &u) {u = v;}
void __fastcall ServerSocketError(TObject* Sender,
TCustomWinSocket* Socket,
TErrorEvent ErrorEvent, int &ErrorCode);
void __fastcall ClientSocketConnect(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ClientSocketRead(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ServerSocketClientRead(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ServerSocketAccept(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ServerSocketClientConnect(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ClientSocketDisconnect(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ClientSocketError(TObject* Sender,
TCustomWinSocket* Socket, TErrorEvent ErrorEvent
, int &ErrorCode);
void __fastcall ServerSocketClientDisconnect(TObject* Sender,
TCustomWinSocket* Socket);
};
#endif
tcpmessager.cpp:
#include "tcpmessager.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
Tcpmessager::Tcpmessager(TComponent* owner)
{
ClientSocket = new TClientSocket(owner);
ServerSocket = new TServerSocket(owner);
ServerSocket->OnAccept = &ServerSocketAccept;
ServerSocket->OnClientConnect = &ServerSocketClientConnect;
ServerSocket->OnClientDisconnect = &ServerSocketClientDisconnect;
ServerSocket->OnClientRead = &ServerSocketClientRead;
ServerSocket->OnClientError = &ServerSocketError;
ClientSocket->OnConnect = &ClientSocketConnect;
ClientSocket->OnDisconnect = &ClientSocketDisconnect;
ClientSocket->OnError = &ClientSocketError;
ClientSocket->OnRead = &ClientSocketRead;
ServerSocket->ServerType = stNonBlocking;
ServerSocket->Port = 1024;
ClientSocket->ClientType = ctNonBlocking;
ClientSocket->Port = 1024;
vectorwasread = false;
currenthost = "";
}
Tcpmessager::~Tcpmessager(void)
{
ServerSocket->Close();
ClientSocket->Close();
delete ServerSocket;
delete ClientSocket;
}
void Tcpmessager::FileListen(void)
{
ClientSocket->Close();
ServerSocket->Open();
}
void Tcpmessager::FileConnect(AnsiString _host)
{
if (ClientSocket->Active) ClientSocket->Active = false;
if (_host.Length() > 0){
ClientSocket->Host = _host;
ClientSocket->Open();
}
}
void Tcpmessager::FileDisconnect(void)
{
ClientSocket->Close();
ServerSocket->Close();
}
bool Tcpmessager::SendData(TCustomWinSocket *Socket, void *Buffer, int
BufSize)
{
LPBYTE pBuf = (LPBYTE) Buffer;
while( BufSize > 0 )
{
int sent = Socket->SendBuf(pBuf, BufSize);
if( sent < 0 )
{
if( WSAGetLastError() != WSAEWOULDBLOCK ) return false;
Application->ProcessMessages();
continue;
}
if( sent == 0 ) // socket disconnected
{
return false;
}
pBuf += sent;
BufSize -= sent;
}
return true;
}
bool Tcpmessager::ReadData(TCustomWinSocket *Socket, void *Buffer, int
BufSize)
{
LPBYTE pBuf = (LPBYTE) Buffer;
while( BufSize > 0 )
{
int read = Socket->ReceiveBuf(pBuf, BufSize);
if( read < 0 )
{
if( WSAGetLastError() != WSAEWOULDBLOCK ) return false;
Application->ProcessMessages();
continue;
}
if( read == 0 ){
// socket disconnected
return false;
}
pBuf += read;
BufSize -= read;
}
return true;
}
bool Tcpmessager::ReadVector(TCustomWinSocket *Socket)
{
int s = 0;
if( ReadData(Socket, &s, sizeof(int)) && s > 0)
{
v.resize(s);
for(int i = 0; i < s; i++)
{
if(!ReadData(Socket, &(v[i]), sizeof(double)) )
return false;
}
}
else return false;
return true;
}
bool Tcpmessager::WriteVector(const vector<double> &u)
{
TCustomWinSocket *Socket;
int n = u.size();
double temp;
if (ClientSocket->Active) Socket = ClientSocket->Socket;
else if (ServerSocket->Socket->ActiveConnections > 0)
Socket = ServerSocket->Socket->Connections[0];
else return false;
if( SendData(Socket, &(n), sizeof(int)) )
{
for(int i = 0; i < n; i++)
{
temp = u[i];
if( !SendData(Socket, &temp, sizeof(double)) )
return false;
}
}
else return false;
return true;
}
void __fastcall Tcpmessager::ClientSocketConnect(TObject* Sender,
TCustomWinSocket* Socket)
{
currenthost = Socket->RemoteHost;
}
void __fastcall Tcpmessager::ClientSocketRead(TObject* Sender,
TCustomWinSocket* Socket)
{
ReadVector(Socket);
vectorwasread = true;
}
void __fastcall Tcpmessager::ServerSocketClientRead(TObject* Sender,
TCustomWinSocket* Socket)
{
ReadVector(Socket);
vectorwasread = true;
}
void __fastcall Tcpmessager::ServerSocketAccept(TObject*
Sender, TCustomWinSocket* Socket)
{
//nothing
}
void __fastcall Tcpmessager::ServerSocketClientConnect(TObject* Sender,
TCustomWinSocket* Socket)
{
currenthost = Socket->RemoteHost;
}
void __fastcall Tcpmessager::ServerSocketClientDisconnect(TObject*
Sender, TCustomWinSocket* Socket)
{
ServerSocket->Close();
ServerSocket->Open();
currenthost = "";
}
void __fastcall Tcpmessager::ClientSocketDisconnect(TObject* Sender,
TCustomWinSocket* Socket)
{
currenthost = "";
}
void __fastcall Tcpmessager::ClientSocketError(TObject* Sender,
TCustomWinSocket* Socket, TErrorEvent ErrorEvent
, int &ErrorCode)
{
//show error msg
ErrorCode = 0;
}
void __fastcall Tcpmessager::ServerSocketError(TObject* Sender,
TCustomWinSocket* Socket,
TErrorEvent ErrorEvent, int &ErrorCode)
{
//show error msg
ErrorCode = 0;
}
Re: Too many calls to OnRead
Author: marko.suonpera
Date: Tue, 14 Feb 2006 09:37
Date: Tue, 14 Feb 2006 09:37
348 lines
10528 bytes
10528 bytes
Ok, I made a new version. Here I create a buffer between the sockets
and read and write by the application. In the sending machine I use the
buffer "send" to hold data. Vector is written into the buffer,
preceeded by its size. "writepos" shows the place where next byte
should be written. "readpos" shows the place where the next byte should
be read when writing to the socket.
In the receiving machine data is read into buffer "rec" whenever
Onread() is called. writepos shows the place where next character
should be written. It is always increased by the amount that
receivebuf() returns. The readpos is not used for this buffer,
readvector() always tries to read the whole vector out of the receive
buffer to the user application. If this succeeds, it shifts the buffer
by the function Rollback() so that the next vector should again start
from the beginning of the buffer.
However, I am a bit confused about receivebuf(). Suppose there is for
example 200 bytes in the socket internal buffer and receivelength()
returns 200. Now should I just try to read 200 bytes? If I just read 10
bytes, which bytes do I get the next time? Is OnRead() called as long
as there is something to read? What is the difference between trying to
read the amount returned by receivelength() and a very big number of
bytes?
And now the code:
#include <ScktComp.hpp>
#include <vector>
using std::vector;
class Buffer
{
public:
char data[5000];
const int bufsize;
int writepos, readpos;
Buffer(): bufsize(5000) { writepos = 0; readpos = 0;}
void RollBack(int);
};
class Tcpmessager
{
private:
TClientSocket *ClientSocket;
TServerSocket *ServerSocket;
vector<double> v;
Buffer rec, send;
bool WriteVectorToBuf(const vector<double> &u);
public:
Tcpmessager(TComponent* owner);
~Tcpmessager(void);
AnsiString currenthost;
void FileListen(void);
void FileConnect(AnsiString _host);
void FileDisconnect(void);
bool SendFromBuf(TCustomWinSocket *Socket);
bool ReadInBuf(TCustomWinSocket *Socket);
bool ReadVector(void);
bool WriteVector(const vector<double> &u);
void GetVector(vector<double> &u) {u = v;}
//void __fastcall ServerSocketError(TObject* Sender, short Number,
AnsiString &Description, int Scode
// , const AnsiString Source, const AnsiString HelpFile, int
HelpContext, Word &CancelDisplay);
void __fastcall ServerSocketError(TObject* Sender,
TCustomWinSocket* Socket,
TErrorEvent ErrorEvent, int &ErrorCode);
void __fastcall ClientSocketConnect(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ClientSocketRead(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ServerSocketClientRead(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ClientSocketWrite(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ServerSocketClientWrite(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ServerSocketAccept(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ServerSocketClientConnect(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ClientSocketDisconnect(TObject* Sender,
TCustomWinSocket* Socket);
void __fastcall ClientSocketError(TObject* Sender,
TCustomWinSocket* Socket, TErrorEvent ErrorEvent
, int &ErrorCode);
void __fastcall ServerSocketClientDisconnect(TObject* Sender,
TCustomWinSocket* Socket);
};
CPP:
Tcpmessager::Tcpmessager(TComponent* owner)
{
ClientSocket = new TClientSocket(owner);
ServerSocket = new TServerSocket(owner);
ServerSocket->OnAccept = &ServerSocketAccept;
ServerSocket->OnClientConnect = &ServerSocketClientConnect;
ServerSocket->OnClientDisconnect = &ServerSocketClientDisconnect;
ServerSocket->OnClientRead = &ServerSocketClientRead;
ServerSocket->OnClientError = &ServerSocketError;
ServerSocket->OnClientWrite = &ServerSocketClientWrite;
ClientSocket->OnConnect = &ClientSocketConnect;
ClientSocket->OnDisconnect = &ClientSocketDisconnect;
ClientSocket->OnError = &ClientSocketError;
ClientSocket->OnRead = &ClientSocketRead;
ClientSocket->OnWrite = &ClientSocketWrite;
ServerSocket->ServerType = stNonBlocking;
ServerSocket->Port = 1024;
ClientSocket->ClientType = ctNonBlocking;
ClientSocket->Port = 1024;
currenthost = "";
}
Tcpmessager::~Tcpmessager(void)
{
ServerSocket->Close();
ClientSocket->Close();
delete ServerSocket;
delete ClientSocket;
}
void Tcpmessager::FileListen(void)
{
ClientSocket->Close();
ServerSocket->Open();
}
void Tcpmessager::FileConnect(AnsiString _host)
{
if (ClientSocket->Active) ClientSocket->Active = false;
if (_host.Length() > 0){
ClientSocket->Host = _host;
ClientSocket->Open();
}
}
void Tcpmessager::FileDisconnect(void)
{
ClientSocket->Close();
ServerSocket->Close();
}
bool Tcpmessager::SendFromBuf(TCustomWinSocket *Socket)
{
LPBYTE pBuf = (LPBYTE) send.data;
int sendamount = send.writepos - send.readpos;
if (sendamount == 0) return true;
int sent = Socket->SendBuf(pBuf+send.readpos, sendamount);
if( sent < 0 )
{
if( WSAGetLastError() != WSAEWOULDBLOCK ) return false;
sent = 0; //WSAEWOULDBLOCK
}
else if( sent == 0 ) // socket disconnected
{
return false;
}
send.readpos += sent;
if (send.readpos > send.bufsize * 0.5) send.RollBack(send.readpos);
return true;
}
bool Tcpmessager::ReadInBuf(TCustomWinSocket *Socket)
{
LPBYTE pBuf = (LPBYTE) (rec.data + rec.writepos);
int k = Socket->ReceiveLength();
int read = Socket->ReceiveBuf(pBuf , k);
if( read < 0 )
{
if( WSAGetLastError() != WSAEWOULDBLOCK ) return false; //real
error
read = 0; //WSAEWOULDBLOCK
}
else if( read == 0 )// socket disconnected
{
return false;
}
rec.writepos += read;
return true;
}
bool Tcpmessager::ReadVector(void)
{
int s = 0;
if (rec.writepos > sizeof(int))
{
s = *((int*)rec.data);
if (s < 0 || s > 500000) return false;
v.resize(s);
}
else return false;
if (rec.writepos < s * sizeof(double) + sizeof(int)) return false;
double *a = (double*)(rec.data + sizeof(int));
for(int i=0;i < s;i++)
v[i] = *(a+i);
//roll read buffer by the suitable amount of bytes
rec.RollBack(s * sizeof(double) + sizeof(int));
return true;
}
bool Tcpmessager::WriteVectorToBuf(const vector<double> &u)
{
int n = u.size();
if (send.bufsize - send.writepos < n*sizeof(double) + sizeof(int))
return false;
*((int*)(send.data + send.writepos)) = n;
send.writepos += sizeof(int);
for(int i = 0; i < n; i++)
{
*((double*)(send.data + send.writepos)) = u[i];
send.writepos += sizeof(double);
}
return true;
}
bool Tcpmessager::WriteVector(const vector<double> &u)
{
TCustomWinSocket *Socket;
if (ClientSocket->Active) Socket = ClientSocket->Socket;
else if (ServerSocket->Socket->ActiveConnections > 0)
Socket = ServerSocket->Socket->Connections[0];
else return false;
if (!WriteVectorToBuf(u)) return false;
//now call sendfrombuf() to send the data
return (SendFromBuf(Socket));
}
void __fastcall Tcpmessager::ClientSocketConnect(TObject* Sender,
TCustomWinSocket* Socket)
{
currenthost = Socket->RemoteHost;
}
void __fastcall Tcpmessager::ClientSocketRead(TObject* Sender,
TCustomWinSocket* Socket)
{
ReadInBuf(Socket);
}
void __fastcall Tcpmessager::ServerSocketClientRead(TObject* Sender,
TCustomWinSocket* Socket)
{
ReadInBuf(Socket);
}
void __fastcall Tcpmessager::ClientSocketWrite(TObject* Sender,
TCustomWinSocket* Socket)
{
SendFromBuf(Socket);
}
void __fastcall Tcpmessager::ServerSocketClientWrite(TObject* Sender,
TCustomWinSocket* Socket)
{
SendFromBuf(Socket);
}
void __fastcall Tcpmessager::ServerSocketAccept(TObject*
Sender, TCustomWinSocket* Socket)
{
//nothing
}
void __fastcall Tcpmessager::ServerSocketClientConnect(TObject* Sender,
TCustomWinSocket* Socket)
{
currenthost = Socket->RemoteHost;
}
void __fastcall Tcpmessager::ServerSocketClientDisconnect(TObject*
Sender, TCustomWinSocket* Socket)
{
ServerSocket->Close();
ServerSocket->Open();
currenthost = "";
}
void __fastcall Tcpmessager::ClientSocketDisconnect(TObject* Sender,
TCustomWinSocket* Socket)
{
currenthost = "";
}
void __fastcall Tcpmessager::ClientSocketError(TObject* Sender,
TCustomWinSocket* Socket, TErrorEvent ErrorEvent
, int &ErrorCode)
{
//show error msg
ErrorCode = 0;
}
void __fastcall Tcpmessager::ServerSocketError(TObject* Sender,
TCustomWinSocket* Socket,
TErrorEvent ErrorEvent, int &ErrorCode)
{
//show error msg
ErrorCode = 0;
}
void Buffer::RollBack(const int a)
{
if (a > 0 && a < bufsize)
{
memcpy(data, data + a, bufsize - a);
readpos -= a;
writepos -= a;
}
}
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads