Python - How to end a socket using a "with as" block - python

I'm learning about sockets and connections and trying to write a simple server Python script that echos a message to a client.
I began with just running a script that prints what it receives from a socket.
So i'm running what i wrote locally and using Putty as a client (so the message isn't printed to the putty session yet).
This is my code:
import socket
HOST = '127.0.0.1'
PORT = 65432
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT)) # bind accepts a tuple of a hostname or address and a port
s.listen()
conn, addr = s.accept() # returns a pair
with conn:
print("Connection started!", conn, addr)
data = conn.recv(1024)
while data:
data = data.decode("UTF-8")
print(data)
# if data == "exit":
# shutdown and close the connection,
# and ofcourse exit the two with as blocks gracefully
data = conn.recv(1024)
print("Connection is closed and the program continued")
Running this works but i have no way of terminating the connection other then killing the server.
I believe that data will always be true since i'm using putty and it seems that even when i'm hitting enter with no text to the connection window, it actually sends this:
b'\r\n'
So I tried placing this inside the commented if statement:
conn.shutdown(socket.SHUT_RDWR)
conn.close()
Hoping this will just make the socket be deleted - but it didn't work.
So what I want to do is to exit the with blocks and deleting the sockets without having to raise any exceptions or make the program stop. I tried doing so using python 3 change to socket that made it usable with with-as statements. I tried just calling the conn.__exit__ or s.__exit__ function but that didn't work also.
How can I close the socket and exit the two with blocks using an input from the user? Is there anything i'm confusing with the socket module here?

Related

python UDP socket check connection

I have a small python console that works over UDP.
The problem I'm having is that if I abruptly disconnect from the client, the connection stays open in netstat (because it's UDP).
I have tried implementing a threading.Timer in the server that asks if the connection is active, and if the client does not respond within that time, the connection closes from the server-side.
This is what I tried
def check_conn(sock: socket.socket):
# sock.settimeout()
sock.send(b"\nAwake?")
try:
ack = sock.recv(1024)
ack = ack.decode("UTF-8")
if ack.strip() == "Yea":
pass
else:
sock.close()
except:
sock.close()
so = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
so.connect((host, port))
t = threading.Timer(10.0, check_conn, [so])
t.start()
data = so.recv(1024)
#rest of the main program
The problem I'm having is that when it asks for the password, two so.recv(1024) are open, and it does not know how to handle them (that's my guess).

Python 2.7 Socket programming ports

I had an exercise of port carousel which means that I need to build a server-client which the server asks the client for a port and then they starting to listen to the port that given, and this is the loop I got a error and I don't know how to fix it.
server:
import socket
import random
def main():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 1729))
server_socket.listen(1)
(client_socket, server_socket) = server_socket.accept()
done = False
while not done:
port = client_socket.recv(4096)
client_socket.send('i got the port' + port)
port = int(port)
if port != 1:
server_socket.bind(('0.0.0.0', port))
continue
else:
done = True
if __name__ == '__main__':
main()
client:
import socket
import random
def main():
print 'hi at anytime enter 1 to break the loop'
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('127.0.0.1', 1729))
done = False
while not done:
port = client_socket.send(raw_input("enter port:"))
data = client_socket.recv(4096)
print data
port = int(port)
if port != 1:
client_socket.connect(('127.0.0.1', port))
continue
else:
done = True
client_socket.close()
if __name__ == '__main__':
main()
the error output for the server:
File "C:/Cyber/ServerFolder/ports_carrousel.py", line 18, in main
server_socket.bind(('0.0.0.0', port))
AttributeError: 'tuple' object has no attribute 'bind'
In your main function, you do the following:
(client_socket, server_socket) = server_socket.accept()
but, server_socket.accept() actually returns two objects. The first, is a socket object, and the second one is a tuple that contains (sourceIPString, sourcePort).
Thus, by using this line of code, outlined above, you are essentially overriding the server_socket by a tuple object.
Notice that later, in line 18, you are trying to access the "bind" function of a socket, but, using a reference to a tuple object, that does not implement such a function.
What you should be doing is something along the lines of
(client_socket, client_connection_info) = server_socket.accept()
and adjust your code accordingly.
Just a couple of things wrong here. First, accept returns a 2-tuple containing the newly-connected socket, and the client's address (which is itself a 2-tuple of IP address and port number). It does not return two sockets. But you're overwriting your server_socket variable with the second returned value. That doesn't make sense and it's why the interpreter is telling you that the 2-tuple has no bind attribute: it's not a socket object. The accept call should look something like this:
client_socket, client_addr = server_socket.accept()
Next, after receiving the new port number from the client, you must create a new socket (you cannot re-use the same listening socket), then bind that new socket to the new port, then listen; finally you can accept a new client connection from the new listening socket.
You should also close sockets you're finished with so that you don't continually leak file descriptors. That means each time you receive a new port number from the client, you should close the client socket, and the listening socket, then create a new listening socket (and bind and listen), then accept the new client socket.
Altogether that will mean restructuring your code in the server significantly. You need to pull the creation of a listening socket down into your main while not done loop.
Another thing to keep in mind. On the client side, immediately after sending the port number to the server, you're attempting a connect to that new port number. However, it's almost certain that your connect request will reach the server before the server has had a chance to create a new listening socket, and bind it. So your client will either need to delay a moment before attempting to connect, or it will need to have logic to retry the connect for some period of time.
EDIT:
Also, you must create a new socket on the client side too when reconnecting. Once a stream socket has been bound to a port (which also happens automatically when you connect), you can never use it to bind or connect to a different address/port.

Problems with sockets

I'm trying to set up a small server where when the client logs in gets some messages.
The server code
import socket
#Networking
s = socket.socket()
print("Network successfully created")
port = 3642
s.bind(('',port))
print("Network has been binded to %s" %(port))
s.listen(5)
print("Waiting for connections")
while True:
c, addr = s.accept()
print("Got a connection from",addr)
c.send(bytes("Thank you for connecting to me. Currently we","utf-8"))
c.send(bytes("Working on the server","utf-8"))
c.close()
This is the client code
# Import socket module
import socket
# Create a socket object
s = socket.socket()
# Define the port on which you want to connect
port = 3642
# connect to the server on local computer
s.connect(('MyIp..', port))
# receive data from the server
print(s.recv(1024))
# close the connection
s.close()
Everything works fine such as the connecting and the first message gets printed, however I can't get the second message to get printed. The one that says working on the server. I have just began learning about sockets and barely know anything about them so the solution probably is obvious it's just
I can't seem to figure it out. Thank you for any responses. (I would appreciate thorough responses)
If the two sent buffers happen to not get consolidated into a single buffer in the recv (which can happen based on timing, which OS you're running and other factors), then it makes sense that you would not see the second buffer because you're only making one recv call. If you want to receive everything the server sent, put the recv in a loop until it returns an empty string. (Empty string indicates end-of-file [i.e. socket closed by the other end].) – Gil Hamilton

Python Socket errno 10054 only when client.py runs

There are some other posts about this issue but none did help me with mine.
I'm trying to build a total simple server - client relationship in python
server.py
#!/usr/bin/python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("127.0.0.1",8889))
s.listen(1)
try:
while True:
client, add = s.accept()
data = client.recv(1024)
if not data:
print 'No data'
print data
finally:
s.close()
client.py
#!/usr/bin/python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1",8889))
try:
while True:
message = 'Foo'
s.send(message)
ans = s.recv(1024)
print ans
finally:
s.close()
I start by running the server first, but when I try to run the client I'm getting this Errno 10054 --> An existing connection was forcibly closed by the remote host
While request the browser with the ip and the related port, I receive some data.
I'm quiet new to networking, so please explain what might be obvious wrong in my code.
EDIT* Main issue is, that the client is somehow wrong, because it returns also an empty string on recv
Thank you in advance
Main issue is, that the client is somehow wrong, because it returns also an empty string on recv
The client isn't receiving anything from the server because the server is not sending anything.
On the server side, after print data, adding client.send(data) will send the string back to the client.
I am guessing:
The server accepts one socket and then does
client, add = s.accept()
data = client.recv(1024)
...
client, add = s.accept()
The client does this in the mean time:
s.send(message)
ans = s.recv(1024) # blocks until timeout
If now an other client connects to the server then client is replaced, the socket garbage collected and closed. s.recv(1024) will then tell that the connection is reset.
Have a look at import select or twisted (google around) to handle multiple connections at once.

Python TCP socket.recv() returns with nothing as soon as connection is made

I'm trying to implement the most basic python TCP server. Windows 8, Python 2.7, firewall is turned off. Code is from here: https://wiki.python.org/moin/TcpCommunication
If I do the client stuff (socket(...), connect(...), send(...)) via python repl, things work fine, ie the server correctly blocks when calling recv.
However if I run the exact same code via python script (both with and without explicitly calling python.exe at windows command line), the recv returns immediately with no data. I read elsewhere on SO this means it's an invalid socket, but I'm not sure what that means or how to check for it. I'm using the socket returned by accept() not the one used to initiate the connection.
I'm trying to block on recv so I can take advantage of the timeout (I don't want to use select module, which BTW also returns immediately) and process some keyboard stuff between attempts to recv, ie user presses 'q' to quit.
In various experiments I've shown that once this occurs, recv will always return immediately (as will select.select(...)) if I put it in a loop, so it's not like the client is sending a single "bad" packet initially. If the client happens to have sent something, then the recv returns with that data, but it certainly doesn't block waiting for data when put in a tight loop.
Is this behavior expected?
Server code:
import sys
import socket
TCP_IP = '192.168.1.10'
TCP_PORT = 5005
BUFFER_SIZE = 20 # Normally 1024, but we want fast response
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connection address:', addr
while 1:
data = conn.recv(BUFFER_SIZE) # This returns immediately with no data, when client connection is run from script and doesn't send() anything, just connects.
if not data:
print "broken"
break
print "received data:", data
conn.send(data) # echo
conn.close()
sys.exit()
Client code:
import sys
import socket
TCP_IP = '192.168.1.10'
TCP_PORT = 5005
BUFFER_SIZE = 1024
MESSAGE = "Hello, World!"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
# Commenting out the following to prove the recv() call on the other
#end returns with nothing instead of blocking indefinitely. If I
#type the rest of this at the REPL the server behaves correctly,
#ie, the recv call blocks forever until socket.send("bla") from client.
#s.send(MESSAGE) data = s.recv(BUFFER_SIZE)
#s.close()
#print "received data:", data
sys.exit()
Yes, this is expected behavior.
The client does not send anything. And it exit as soon as it connect to the server; cause disconnection.
socket.recv returns an empty string if the peer performed shutdown (disconnect).
While, in the REPL, the socket is not closed until you issue sys.exit() or you quit the interactive shell.

Categories

Resources