I'm want to be able to re-connect to a idSimpleServer after one client connects to it and then disconnects. The first client can connect and disconnect no problem but the next client can't. I did a simple test procedure to demonstrate it my problem.
procedure Tfrmmain.btnBlockingClick(Sender: TObject);
begin
Server1.BeginListen;
Server1.Listen;
CodeSite.Send(csmLevel2, 'Listen');
CodeSite.Send(csmLevel2, 'Server1.IOHandler.Connected', Server1.IOHandler.Connected);
try
while (Server1.Connected) do
begin
while Server1.IOHandler.CheckForDataOnSource() do
begin
CodeSite.Send(csmLevel3, 'InputBufferAsString', Server1.IOHandler.InputBufferAsString);
Server1.IOHandler.WriteLn('0006CANPDD');
end;
end;
finally
Server1.Disconnect;
CodeSite.Send(csmLevel4, 'Finally');
end;
end;
This give the following results in my codesite log:
Listen
Server1.IOHandler.Connected = True
Finally
Listen
Server1.IOHandler.Connected = False
Finally
Notice the second connection doesn't seem to bind the IOHandler properly. Not sure where I should be looking. Any ideas?
Thanks
Steve
The problem is that you are reusing the same TIdSimpleServer object each time.
After the first disconnect, the same IOHandler is reused for the next connection, but the IOHandler.ClosedGracefully property remains true from the earlier connection becaue it is not being reset each time. The ClosedGracefully property is reset only by the IOHander.Open() method, which TIdSimpleServer calls only when it creates a new IOHandler. Disconnect() does not free the IOHandler, but it does call IOHandler.Close().
The missing call to Open() on subsequent connections looks like a bug to me, so I have checked in a fix for it to Indy's SVN (rev 5103).
You can either upgrade to the latest SVN release, or else you will have to destroy the TIdSimpleServer.IOHandler (or the TIdSimpleServer itself) in between each connection.
Related
I want to block certain client "OnConnect" to my Server, but I am not sure which event is best to use and how to find the remote IP...
In your app's code, using the OnConnect event is the simplest choice. You can get the client's IP from the Binding.PeerIP property of the provided AContext parameter, eg:
procedure TMyForm.IdHTTPServer1Connect(AContext: TIdContext);
begin
if (AContext.Binding.PeerIP is blacklisted) then
AContext.Connection.Disconnect; // or raise an Exception...
end;
However, a better choice is to put your server app behind a firewall that blocks connections by the desired IPs from reaching TIdHTTPServer in the first place.
Here my first steps with Oracle Advanced Queueing...
Szenario: I have a running application where many, many multiple independ processes report back to a central controller to handle the next steps. Simplified the processes are started via cron or via callback of a just finished process.The callbacks are from remote hosts via http -> php -> DB, basicly one http-call after the process has finished on the remote host.
The complete controller logic was written in pl/sql with a singleton concept in mind, so only one process should execute the controller logic at the same time. In fact in 99% of all calls this is not necessary, but that's not the kind of thing I could change at the moment (nor the architecture in general).
To ensure this there is actually a bad mutex implementation, pseudo-code
$mutex = false;
while( not $mutex )
{
$mutex = getMutex();
if( $mutex )
executeController();
else
sleep(5);
}
Wherein the mutex is a one field table having the values 0 (=> "free") or 1 ( => "busy" )
The result of this "beautiful" contstruction is log-file full of "Hey! Got no mutex! Waiting...". And the more processes wait, the longer they wait with no control of who's next. Sometimes the load gets so heavy that the apache first forks and finally dies...
Solution
So my first "operation" would be to replace the mutex with Oracle Advanced Queueing with the controller as single-consumer. Benefits: No more "busy waiting" within the apache layer, strict first come first serve.
( Because all the DB-Actions take place in the same oracle-schema, this could be achieved with standard-objects, pl/sql-methods as well. But why reinvent the wheel, if there are dbms-packages?)
As far as I read using the listen-feature (polling the queued items) in this context is far better than the registration-feaure (scheduling an action when a message arrives).
Basicly everything works fine, i managed to:
create the message type
create the queue-table
create the queue
start the queue
add USER as subscriber
create a procedure for enqueueing
create a procedure for processing & dequeueing
create a procedure for listening to the queue and calling the "process & dequeue"-function when a message arrives.
Of course the listener shall be active 24/7, so i specified no "wait" time. In general depending on the time of the day he will get "something to do" at least every few minutes, more likely every few seconds, sometimes more.
Now here is my problem (if it actually is a problem), i just wrote it according to the examples i found so far:
CREATE OR REPLACE PROCEDURE demo_aq_listener IS
qlist dbms_aq.aq$_agent_list_t;
agent_w_msg sys.aq$_agent;
BEGIN
qlist(0) := sys.aq$_agent(USER, 'demo_aq_queue', NULL);
LOOP
dbms_aq.listen(agent_list => qlist, agent => agent_w_msg);
DEMO_AQ_DEQUEUE();--process & dequeue
END LOOP;
END;
/
Calling the procedure basically does what i expect: It stays "up" and prosseces the queued messages.
But is this the way to do this? What does it do if there are no queued messages? "Sleeping" within the dbms_aq.listen-routine or "Looping as fast as it can", so that I just have implemented another way of "busy waiting"? Might there be a timeout (maybe on oss-level or elsewhere) i just didn't reach?
Here is the complete code with queue-definition etc.: demo_dbms_aq_with_listener.sql
UPDATE
Through further testing i just realized that it seems, that i got a far greater lack of understanding then i hoped :(
On "execution level" don't using the listener at all and just looping the dequeue function has the same effect: It waits for the first/next message
CREATE OR REPLACE PROCEDURE demo_aq_listener IS
BEGIN
LOOP
DEMO_AQ_DEQUEUE();
END LOOP;
END;
/
At least this is easier to test, calling only
BEGIN
DEMO_AQ_DEQUEUE();
END;
/
Also just waits for the first message. Which leaves me totally confused wether I need the listener at all and if what i'am doing does make any sense at all :(
Conclusion
I don't need the listener at all, because i have a single consumer who can treat all messages in the same way.
But the key/core Question stays the same: Is it ok to keep DBMS_AQ.DEQUEUE on "maybe active waiting" in a loop knowing it'll get messages all day long in short intervalls?
(you'll find DEMO_AQ_DEQUEUE() in linked sql-file above)
Better late than never, everything's fine, it is idle waiting:
1) Whilst the DEQUEUE is in sleep mode (WAIT FOREVER), I can see the session is waiting on the event - "Streams AQ: waiting for messages in the queue", that is an IDLE wait class and not actually consuming ANY resources, correct ?
Correct. It's similar to waiting on a row lock on a table. You just "sit there"
https://asktom.oracle.com/pls/apex/asktom.search?tag=writing-a-stand-alone-application-to-continuously-monitor-a-database-queue-aq
i have this code to check connection to my server
so code is like this:
function CheckInternet(ssip:string): boolean;
begin
result:=false;
with form1.IdTCPClient1 do
try
ReadTimeout:=2000;
ConnectTimeout:=1000;
Port:=80;
Host:=ssip;
Connect;
Disconnect;
result:=true;
except
on E:EIdSocketError do
result:=false;
end;
end;
after running:
if server is online every thing is ok
but if server is online i got a lot of this error:
there is not difference in debug or release mode! both have error
also in android this cause two app crash and dont handling remain code!!..
how can i avoid this error?
What you see can happen only if you are calling CheckInternet() in a loop in the main UI thread and not catching raised exceptions. The popup messages are being displayed by a default exception handler within FMX when it catches an uncaught exception.
EIdSocketError is not the only type of exception that Connect() can raise. There are several other possible types, which you are not catching. You should remove the filter from your except block:
function CheckInternet(ssip:string): boolean;
begin
result:=false;
with form1.IdTCPClient1 do
try
ConnectTimeout:=1000;
Port:=80;
Host:=ssip;
Connect;
Disconnect;
result:=true;
except
result:=false;
end;
end;
Please suppose that we have a procedure inside a package:
MY_PACKAGE.MY_PROCEDURE
This procedure could be launched from many users.
How can I modify the procedure in order to detect if the procedure is at present running since launched from another user?
What is the safest way to detect it?
Thank you for considering my request.
EDIT 01: "It'll depend on why you need to know if a proc is already running or not" ==> If the procedure is at present running, it WON'T be launched again.
You can use the DBMS_APPLICATION_INFO package for such information.
PROCEDURE MY_PROCEDURE(..) IS
BEGIN
DBMS_APPLICATION_INFO.SET_CLIENT_INFO('MY_PACKAGE.MY_PROCEDURE running');
... All your stuff
DBMS_APPLICATION_INFO.SET_CLIENT_INFO(NULL);
EXCEPTION
WHEN OTHERS THEN
DBMS_APPLICATION_INFO.SET_CLIENT_INFO(NULL);
RAISE;
END MY_PROCEDURE;
In order to check it, you can select V$SESSION View:
SELECT *
FROM v$session
WHERE client_info = 'MY_PACKAGE.MY_PROCEDURE running';
If you get any records then the procedure is running.
Based on what others have mentioned and a quick perusal of the DBMS_LOCK package header it appears that you can use the various DBMS_LOCK routines to accomplish what you're trying to do. If I'm reading the header comments correctly you'd want to call ALLOCATE_UNIQUE to get a handle to a unique, named lock, then you'd call REQUEST with the locking mode set to 'x' (Exclusive) to try to grab the lock. If the REQUEST call returns 0 you can go ahead and run your routine. When done, call RELEASE to make the lock available to the next caller.
Best of luck.
I have a ruby tcpsocket client that is connected to a server.
How can I check to see if the socket is connected before I send the data ?
Do I try to "rescue" a disconnected tcpsocket, reconnect and then resend ? if so, does anyone have a simple code sample as I don't know where to begin :(
I was quite proud that I managed to get a persistent connected client tcpsocket in rails. Then the server decided to kill the client and it all fell apart ;)
edit
I've used this code to get round some of the problems - it will try to reconnect if not connected, but won't handle the case if the server is down (it will keep retrying). Is this the start of the right approach ? Thanks
def self.write(data)
begin
##my_connection.write(data)
rescue Exception => e
##my_connection = TCPSocket.new 'localhost', 8192
retry
end
end
What I usually do in these types of scenarios is keep track of consecutive retries in a variable and have some other variable that sets the retry roof. Once we hit the roof, throw some type of exception that indicates there is a network or server problem. You'll want to reset the retry count variable on success of course.