I need to send a RST flag in one socket, is it possible?
When I close the TIdTCPClient, the TCP server program tells me that the connection is still alive, and after 2 minutes the connection disappears.
I'm doing this :
TCPCliente := TIdTCPClient.Create(nil);
TCPCliente.Host := edtIP.Text;
TCPCliente.Port := 492;
TCPCliente.ConnectTimeout := 1000;
TCPCliente.Connect;
TCPCliente.Socket.WriteLnRFC(TextoEnvio, IndyTextEncoding_8Bit);
Texto := TCPCliente.Socket.ReadLn(IndyTextEncoding_8Bit);
TCPCliente.Socket.Close;
TCPCliente.Disconnect;
TCPCliente.Free;
I'm using RAD Studio XE8.
Related
I have a Timer and want send a message to each client of ListView to determine a ping time for example. Then i have this following code:
procedure TMainForm.Timer1Timer(Sender: TObject);
var
i: Integer;
begin
try
for i := 0 to ListView1.Items.count - 1 do
begin
ListView1.Items.Item[i].SubItems.Objects[2] := TObject(GetTickCount);
ServerSocket1.Socket.Connections[i].SendText('ping' + #13#10);
end;
except
exit;
end;
end;
Before send, could be more appropriate check if the client is really connected or some like this. How make this? Thank's in advance.
There is no need to check for a connection. If the client were actually disconnected, it would not be in the server's Connections[] list anymore when your OnTimer handler is triggered. You should have an OnClientDisconnect handler assigned to the TServerSocket to remove the client from the TListView.
If, for some reason, the client were still in the Connections[] list (ie, because the underlying connection has been lost but TServerSocket hasn't detected it yet), then the socket would simply cache all outgoing data until its outbound buffer fills up, then it would start returning WSAWOULDBLOCK errors for each send. Eventually, the OS will timeout the dead connection and TServerSocket will remove it from the Connections[] list, triggering the OnClientDisconnect event.
At the very least, in the code you have shown, you should update your send loop to Close() any socket that actually fails to send, thus triggering the OnClientDisconnect event to remove that client from the TListView, eg:
procedure TMainForm.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
var
Item: TListItem;
begin
Item := ListView1.Items.Add;
Item.Data := Socket;
...
end;
procedure TMainForm.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
var
Item: TListItem;
begin
Item := ListView1.FindData(0, Socket, True, False);
if Item <> nil then
Item.Delete;
end;
procedure TMainForm.Timer1Timer(Sender: TObject);
const
s: AnsiString = 'ping' + #13#10;
var
Item: TListItem;
Socket: TCustomWinSocket;
p: PAnsiChar;
i, len, sent: Integer;
begin
for i := 0 to ListView1.Items.Count - 1 do
begin
Item := ListView1.Items[i];
Item.SubItems.Objects[2] := TObject(GetTickCount);
Socket := TCustomWinSocket(Item.Data);
try
// SendText() does not handle partial sends, or Unicode strings...
//Socket.SendText('ping' + #13#10);
p := PAnsiChar(s);
len := Length(s);
repeat
sent := Socket.SendBuf(p^, len);
if sent = -1 then
being
if WSAGetLastError() <> WSAEWOULDBLOCK then
Break;
// TODO: stop trying after several attempts fail...
Continue;
end;
Inc(p, sent);
Dec(len, sent);
until len = 0;
if len = 0 then
Continue;
except
end;
Socket.Close;
end;
end;
I'm writing a simple program in Golang to capture TCP/IP packets using raw sockets:
package main
import (
"fmt"
"log"
"net"
)
func main() {
netaddr, err := net.ResolveIPAddr("ip", "127.0.0.1")
if err != nil {
log.Fatal(err)
}
conn, err := net.ListenIP("ip:tcp", netaddr)
if err != nil {
log.Fatal(err)
}
packet := make([]byte, 64*1024)
numPackets := 0
totalLen := 0
for {
packetLen, _, err := conn.ReadFrom(packet)
if err != nil {
log.Fatal(err)
}
dataOffsetWords := (packet[12] & 0xF0) >> 4
dataOffset := 4 * dataOffsetWords
payload := packet[dataOffset:packetLen]
numPackets += 1
totalLen += len(payload)
fmt.Println("Num packets:", numPackets, ", Total len:", totalLen)
}
}
When I compare the number of packets which the program receives and the total amount of data they contain to the number of packets Wiresharks sees and the total data transmitted, I know I've lost 15-30 % of all packets and data on every run.
Why?
The only thing that comes to my mind is that the application is not fast enough to receive the packets, but that's odd. (I'm communicating on localhost and sending ~ 17 MB of data.) Goreplay however uses something similar and works.
The traffic I'm receiving is created by curl-ing onto a locally running Python server (http.server) and sending a huge file in the request body. The Python server downloads the whole body successfully.
My initial suspiction was right: by modifying the receiving Python server so that it does not read all incoming data at once:
post_body = self.rfile.read(content_len)
but rather in a loop with a 10 ms delay between iterations:
while (total_len < content_len):
post_body = self.rfile.read(min(16536, content_len - total_len))
total_len += len(post_body)
time.sleep(1 / 100.)
I receive all data in the Golang and the number of packets processed is approximately te same (I assume there will only rarely be a match as the packets received in Golang were already processed, i.e. put back into order. Or at least I hope, because there's no much documentation.)
Also, the packet loss changes when the delay is adjusted.
Is there a better login method in AutoHotkey to do this? Or perhaps a way to allow unsecured logins to Google? I have enabled less secure apps on the Google account settings.
AutoHotkey error:
This message could not be sent to SMTP server. The transport error codwe was 0x80040217. The server response was not available.
Gmail response (some info redacted):
Sign-in attempt prevented
Hi [redacted],
Someone just tried to sign in to your Google Account [redacted]#gmail.com from an app that doesn't meet modern security standards.
...
AutoHotkey script (some info redacted):
pmsg := ComObjCreate("CDO.Message")
pmsg.From := """John Doe"" <John.Doe#gmail.com>"
pmsg.To := "Jane.Doe#gmail.com, Joe.Schmo#gmx.com"
pmsg.BCC := "" ; Blind Carbon Copy, Invisible for all, same syntax as CC
pmsg.CC := "redacted#gmail.com" ; Somebody#somewhere.com, Other-somebody#somewhere.com
pmsg.Subject := "See below"
;pmsg.TextBody := ""
pmsg.HtmlBody := "<html><head><title>Hello</title></head><body><table border='1'><tr><td>row 1, cell 1</td><td>row 1, cell 2</td></tr><tr><td>row 2, cell 1</td><td>row 2, cell 2</td></tr></table> </body></html>"
;sAttach := "" ; can add multiple attachments, the delimiter is |
fields := Object()
fields.smtpserver := "smtp.gmail.com" ; specify your SMTP server
fields.smtpserverport := 465 ; 25
fields.smtpusessl := True ; False
fields.sendusing := 2 ; cdoSendUsingPort
fields.smtpauthenticate := 1 ; cdoBasic
fields.sendusername := "redacted#gmail.com"
fields.sendpassword := "redacted"
fields.smtpconnectiontimeout := 60
schema := "http://schemas.microsoft.com/cdo/configuration/"
pfld := pmsg.Configuration.Fields
For field,value in fields
pfld.Item(schema . field) := value
pfld.Update()
Loop, Parse, sAttach, |, %A_Space%%A_Tab%
pmsg.AddAttachment(A_LoopField)
pmsg.Send()
return
Hmm, maybe you need the quotes around the formed schema-field:
pfld.Item("""" . schema . field . """") := value
Or try '"' to get the quotes.
Also, try port 25 and/or username w/o the #gmail part (but I think what you have is correct for gmail).
Hth,
Hey I'm working in project, but i cant manage to connect from a IP not located in the same network (LAN). The code bellow works fine locally, but I cant figure out how to make work from different IP located in different locations?, and google cant see to help, any ideas?
class
RG_NETWORK_SERVER
inherit
STORABLE
NETWORK_SERVER
redefine
receive,
received,
close
end
create
make_server
feature
connections: LINKED_LIST [RG_CONNECTION]
max_to_poll: INTEGER
message_out: RG_MESSAGE
received: detachable RG_MESSAGE
poll: MEDIUM_POLLER
make_server
require
local
l_message_out: detachable like message_out
l_connections: detachable like connections
l_in: detachable like in
do
make (1337)
max_to_poll := 1
create poll.make_read_only
in.set_non_blocking
l_in := in
create l_message_out.make
message_out := l_message_out
create l_connections.make
connections := l_connections
connections.compare_objects
execute
end
process_message
local
stop: BOOLEAN
pos: INTEGER
do
from
connections.start
until
connections.after or stop
loop
if connections.item.is_waiting then
if attached {RG_MESSAGE} retrieved (connections.item.active_medium) as l_message_in then
if l_message_in.new then
connections.item.set_client_name (l_message_in.client_name)
create message_out.make
message_out.set_client_name (l_message_in.client_name)
message_out.extend (l_message_in.client_name)
message_out.extend (" has just joined the server%N")
elseif l_message_in.over then
poll.remove_associated_read_command (connections.item.active_medium)
connections.remove
create message_out.make
message_out.set_client_name (l_message_in.client_name)
message_out.extend (l_message_in.client_name)
message_out.extend (" has just gone%N")
stop := True
else
message_out := l_message_in.deep_twin
message_out.put_front (" has just sent that :%N")
message_out.put_front (message_out.client_name)
message_out.put_front ("-> ")
end
pos := connections.index
-- l_message_in.print_message
message_out.print_message
broadcast
connections.go_i_th (pos)
-- Post status to client
create message_out.make
message_out.extend ("Got it! %N")
message_out.independent_store (connections.item.active_medium)
end
end
if not stop then
connections.forth
end
end
end
broadcast
local
client_name: detachable STRING
do
client_name := message_out.client_name
if client_name /= Void then
from
connections.start
until
connections.after
loop
if connections.item.client_name /~ client_name then
message_out.independent_store (connections.item.active_medium)
end
connections.forth
end
end
end
receive
do
in.accept
if attached {like outflow} in.accepted as l_outflow then
l_outflow.set_blocking
new_client (l_outflow)
end
from
connections.start
until
connections.after
loop
connections.item.initialize
connections.forth
end
poll.execute (max_to_poll, 1000)
end
new_client (a_flow: attached like outflow)
local
new_connection: RG_CONNECTION
do
if max_to_poll <= a_flow.descriptor then
max_to_poll := a_flow.descriptor + 1
end
create new_connection.make (a_flow)
connections.extend (new_connection)
create message_out.make
message_out.extend ("Welcome! %N")
message_out.independent_store (a_flow)
poll.put_read_command (new_connection)
end
end
and the client:
class
RG_NETWORK_CLIENT
inherit
NETWORK_CLIENT
redefine
received
end
create
make_join
feature
make_join(ip:STRING)
require
is_ip_void : ip /= Void
local
l_client_name: detachable like client_name
do
check_name
l_client_name := client_name
make (1337, ip)
max_to_poll := in_out.descriptor + 1
create connection.make (in_out)
create poll.make_read_only
poll.put_read_command (connection)
send_name_to_server
auto_scan_server
processing
end
feature
connection: RG_CONNECTION
std_input: detachable RG_CONNECTION
message_out: RG_MESSAGE
received: detachable RG_MESSAGE
client_name: STRING
over: BOOLEAN
poll: MEDIUM_POLLER
input_poll: detachable MEDIUM_POLLER
max_to_poll: INTEGER
waiting:BOOLEAN
send_name_to_server
do
create message_out.make
message_out.set_client_name (client_name)
message_out.set_new (True)
message_out.set_over (False)
send (message_out)
end
processing
do
from
over := False
until
over
loop
scan_from_server
if not over then
read_content
end
end
cleanup
end
read_content
local
temp: detachable STRING
do
io.put_string ("Enter message: ")
io.readline
temp := io.laststring
if temp /= Void and not temp.is_empty then
if temp.is_equal ("bye") then
over := True
end
create message_out.make
message_out.extend (temp)
message_out.extend ("%N")
message_out.set_over (over)
message_out.set_client_name (client_name)
message_out.set_new (False)
send (message_out)
auto_scan_server
end
end
check_name
local
l_name: detachable STRING
do
io.putstring ("Enter your name : ")
io.readline
l_name := io.laststring
check
l_name_attached: l_name /= Void
end
client_name := l_name.twin
end
scan_from_server
local
l_received: like received
do
connection.initialize
poll.execute (max_to_poll, 1000)
if connection.is_waiting then
receive
l_received := received
if l_received /= Void then
waiting := FALSE
l_received.print_message
if l_received.over then
over := True
end
end
end
end
auto_scan_server
do
waiting := True
from until not waiting
loop
scan_from_server
end
end
end
The work around is the work with the samples provided from Eiffel, it works as longest the two persons are connected in the same network. for example as follow:
Here we define if the user has receive the message or is waiting for one, also redefine the poll_command to be able to use it.
inherit
POLL_COMMAND
redefine
make
end
create
make
feature {NONE} -- Initialization
make (s: IO_MEDIUM)
do
Precursor (s)
create client_name.make_empty
end
feature
is_waiting: BOOLEAN
client_name: STRING
execute (arg: ANY)
do
is_waiting := True
end
initialize
do
is_waiting := False
end
set_client_name (s: STRING)
require
s_exists: s /= Void
do
client_name := s.twin
end
end
Then following the chat sample, that can be found in the samples folder, in the message handler, we create the follow:
set_client_name (s: STRING)
require
s_not_void: s /= Void
do
client_name := s.twin
end
set_new (flag: BOOLEAN)
do
new := flag
end
Later in the connection class we are able to connect to a server ip, which it can be pass true command line or via GUI input.
make_join (name: STRING; ip: STRING; gc: RG_CLIENT)
require
is_ip_void: ip /= Void
do
-- Connects to IP on port 1337
make (1337, ip)
max_to_poll := in_out.descriptor + 1
create connection.make (in_out)
create poll.make_read_only
poll.put_read_command (connection)
-- Sets client name and refrence
client_name := name
p_client := gc
-- Sends name to server and receives ID
client_id := send_name_to_server
-- Launches instance as thread
make_thread
launch
execute
end
Then in the server class...
make_server (gs: RG_SERVER)
local
l_message_out: detachable like message_out
l_connections: detachable like connections
l_in: detachable like in
do
-- Instantiate reference and create server listening on port 1337
game_server := gs
make (1337)
max_to_poll := 1
create poll.make_read_only
in.set_non_blocking
l_in := in
create l_connections.make
connections := l_connections
connections.compare_objects
-- Launches instance as tread
make_thread
launch
end
There is a bit more code, but this is a good sample in how to do it, there must be a method to handle the connections, but this is a good start, also remember that all this is based on their samples, chat sample is a good point of start..
enjoy eiffel while is not crashing .
How do you use network sockets in Pascal?
Here's an example taken from http://www.bastisoft.de/programmierung/pascal/pasinet.html
program daytime;
{ Simple client program }
uses
sockets, inetaux, myerror;
const
RemotePort : Word = 13;
var
Sock : LongInt;
sAddr : TInetSockAddr;
sin, sout : Text;
Line : String;
begin
if ParamCount = 0 then GenError('Supply IP address as parameter.');
with sAddr do
begin
Family := af_inet;
Port := htons(RemotePort);
Addr := StrToAddr(ParamStr(1));
if Addr = 0 then GenError('Not a valid IP address.');
end;
Sock := Socket(af_inet, sock_stream, 0);
if Sock = -1 then SockError('Socket: ');
if not Connect(Sock, sAddr, sizeof(sAddr)) then SockError('Connect: ');
Sock2Text(Sock, sin, sout);
Reset(sin);
Rewrite(sout);
while not eof(sin) do
begin
Readln(sin, Line);
Writeln(Line);
end;
Close(sin);
Close(sout);
Shutdown(Sock, 2);
end.
If you're using FPC or Lazarus(which is basically a rad IDE for FPC and a clone of delphi) you could use the Synapse socket library. It's amazing.
If you are using Delphi, I highly recommend Indy sockets, a set of classes for easy manipulation of sockets and many other internet protocols (HTTP, FTP, NTP, POP3 etc.)
You cannot use OpenSSL with Indy version 10.5 that shippes with Delphi 2007. You have to download version 10,6 from http://www.indyproject.org/ and install it into the IDE.
Note that other packages might use Indy, like RemObjects, and therefore they have to be re-compiled too and this can be tricky due to cross-references.