Based on the highest-rated answer to this post:
Socket : 2 way communication in python
And the docks:
https://docs.python.org/3/library/socket.html#targetText=socket.makefile
I'm attempting to work out how to use socket.makefile to send/receive over a socket. Here is what I have so far:
Server.py:
# Server.py
import socket
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# bind the socket
sock.bind((HOST, PORT))
print('socket binded')
# start the socket listening
sock.listen(10)
print('socket now listening')
# accept the socket response from the client, get the connection object
conn, addr = sock.accept() # Note: execution waits here until the client calls sock.connect()
print('socket accepted, got connection object')
sockFile = sock.makefile()
while True:
message = sockFile.readline()
print('received: ' + str(message))
# end while
# end main
if __name__ == '__main__':
main()
Client.py:
# Client.py
import socket
import time
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# connect the socket
sock.connect((HOST, PORT)) # Note: if execution gets here before the server starts up, this line will cause a crash
print('socket connected')
sockFile = sock.makefile(mode='w')
myCounter = 0
while True:
message = 'message ' + str(myCounter)
print('sending: ' + message)
sockFile.write(message)
myCounter += 1
time.sleep(1) # wait for 1 sec before sending next text message
# end while
# end main
if __name__ == '__main__':
main()
Right now if I start the server, then the client from separate command prompts, the client seems to be working:
Client.py output:
$ python3 Client.py
socket instantiated
socket connected
sending: message 0
sending: message 1
sending: message 2
sending: message 3
sending: message 4
sending: message 5
But the server fails with the error:
$ python3 Server.py
socket instantiated
socket binded
socket now listening
socket accepted, got connection object
Traceback (most recent call last):
File "Server.py", line 38, in <module>
main()
File "Server.py", line 32, in main
message = sockFile.readline()
File "/usr/lib/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
OSError: [Errno 107] Transport endpoint is not connected
How can I connect the transport endpoint successfully on the server when using socket.makefile? I'm not sure what the syntax is in this case. I don't end up using conn and addr as I would on the server with the more traditional way of doing it, perhaps that's where I'm going wrong?
--- Edit ---
In Server.py I tried to use the connection with the makefile() function like so:
.
.
.
# accept the socket response from the client, get the connection object
conn, addr = sock.accept() # Note: execution waits here until the client calls sock.connect()
print('socket accepted, got connection object')
connFile = conn.makefile()
while True:
message = connFile.readline()
print('received: ' + str(message))
# end while
.
.
.
But this does not work either, Client.py still works as before but now Server.py just hangs:
$ python3 Server.py
socket instantiated
socket binded
socket now listening
socket accepted, got connection object
(hangs here forever)
--- Edit2 ---
Now I'm really confused. Based on this post:
https://bugs.python.org/issue35928
I pretty much copied the posters code so Server.py now looks like this:
# Server.py
import socket
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
print(f'Waiting for connection on port {s.getsockname()[1]}')
s.listen(1)
conn, addr = s.accept()
print(f'Connected by {addr}')
with conn:
f = conn.makefile(mode='rw')
while True:
print('before f.readline()')
m = f.readline()
print('after f.readline()')
print(f'msg: {m!r}')
if not m:
exit(0)
f.write(m)
f.flush()
# end main
if __name__ == '__main__':
main()
And Server.py still hangs on the read!!
$ python3 Server.py
Waiting for connection on port 65439
Connected by ('127.0.0.1', 47536)
before f.readline()
According to the last post in the responses the poster's original concern is supposedly fixed so this should work now. I'm still not sure how to accomplish this.
--- Edit3 ---
I'm using Ubuntu 18.04.3 with the latest updates and Python 3.6.9 if that matters
In your server code:
conn, addr = sock.accept()
calls sock.connect()
sockFile = sock.makefile()
while True:
message = sockFile.readline()
You made a client socket (conn) but you never used it.
The client is writing so you should be reading from the client socket (conn)
Also I think you should call accept from inside the while loop.
while True:
conn, addr = sock.accept()
sockFile = conn.makefile()
message = sockFile.readline()
Socket does not work this way. It is supposed to complete one message and to be destroyed. See "Socket Programming HOWTO" by Gordon McMillan on Python documentation page. So you could organize your code like below. This transmits one message and then shutdown/close.
# server.py
import socket
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# bind the socket
sock.bind((HOST, PORT))
print('socket binded')
# start the socket listening
sock.listen(10)
print('socket now listening')
# accept the socket response from the client, get the connection object
conn, addr = sock.accept() # Note: execution waits here until the client calls sock.connect()
print('socket accepted, got connection object')
sockFile = conn.makefile()
# while True:
message = sockFile.readline()
print('received: ' + str(message))
# end while
# end main
if __name__ == '__main__':
main()
and client code,
# client.py
import socket
import time
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# connect the socket
sock.connect((HOST, PORT)) # Note: if execution gets here before the server starts up, this line will cause a crash
print('socket connected')
sockFile = sock.makefile(mode='w')
myCounter = 0
# while True:
message = 'message ' + str(myCounter) + '\r\n'
print('sending: ' + message)
sockFile.write(message)
# sockFile.flush()
sockFile.close()
# myCounter += 1
# time.sleep(1) # wait for 1 sec before sending next text message
# end while
# end main
if __name__ == '__main__':
main()
If you really want to transmit multiple messages in one script, create one new socket for each message. See code below,
# server_multi.py
import socket
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# bind the socket
sock.bind((HOST, PORT))
print('socket binded')
# start the socket listening
sock.listen(10)
print('socket now listening')
while True:
# accept the socket response from the client, get the connection object
conn, addr = sock.accept() # Note: execution waits here until the client calls sock.connect()
print('socket accepted, got connection object')
sockFile = conn.makefile()
# while True:
message = sockFile.readline()
print('received: ' + str(message))
conn.close()
# end while
# end main
if __name__ == '__main__':
main()
and the client code looks like this,
# client_multi.py
import socket
import time
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
myCounter = 0
while True:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# connect the socket
sock.connect((HOST, PORT)) # Note: if execution gets here before the server starts up, this line will cause a crash
print('socket connected')
sockFile = sock.makefile(mode='w')
# while True:
message = 'message ' + str(myCounter) + '\r\n'
print('sending: ' + message)
sockFile.write(message)
# sockFile.flush()
sockFile.close()
myCounter += 1
time.sleep(1) # wait for 1 sec before sending next text message
# end while
# end main
if __name__ == '__main__':
main()
Related
I am currently working on a problem where I need to have a server handle multiple clients at the same time. I have a server.py file and a client.py file. Here is a snippet from server.py:
connections = []
addresses = []
for c in connections:
c.close()
del connections[:]
del addresses[:] #clears anything pre-existing
while True:
try:
csock, address = s.accept() #takes in connection and stores info
s.setblocking(1) #prevents timeout
connections.append(csock)
addresses.append(address)
print(f"Connection from {address} has been established!")
except:
print("Error has occurred")
When I run my server in terminal and then connect to it with a client. It behaves as I would expect, with it printing out Connection from ('192.168.1.84', 50824) has been established!.
When I open up another terminal and run client.py to make an additional connection, nothing happens. That is, until I close out of my first client process and then the server prints out
Error occurred
Connection from ('192.168.1.84', 50826) has been established!
I can kind of see what is happening here, but I'm very new to networking and I'm not super great at multithreading, so could anyone give me some insight as to what's going on and what I can do to make these processes run simultaneously as I would expect?
After s.accept() you should use threading to run code in separated thread - and this thread should continue connection with client. At the same time main thread may go back to s.accept() to wait for next client.
Minimal working code with some extra settings.
Server:
import socket
import threading
import time
# --- functions ---
def handle_client(conn, addr):
print("[thread] starting")
# recv message
message = conn.recv(1024)
message = message.decode()
print("[thread] client:", addr, 'recv:', message)
# simulate longer work
time.sleep(5)
# send answer
message = "Bye!"
message = message.encode()
conn.send(message)
print("[thread] client:", addr, 'send:', message)
conn.close()
print("[thread] ending")
# --- main ---
host = '0.0.0.0'
port = 8080
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # solution for "[Error 89] Address already in use". Use before bind()
s.bind((host, port))
s.listen(1)
all_threads = []
try:
while True:
print("Waiting for client")
conn, addr = s.accept()
print("Client:", addr)
t = threading.Thread(target=handle_client, args=(conn, addr))
t.start()
all_threads.append(t)
except KeyboardInterrupt:
print("Stopped by Ctrl+C")
finally:
if s:
s.close()
for t in all_threads:
t.join()
Client (for test)
import socket
# --- main ---
host = '0.0.0.0'
port = 8080
s = socket.socket()
s.connect((host, port))
print("Connected to the server")
message = "Hello"
print('send:', message)
message = message.encode()
s.send(message)
message = s.recv(1024)
message = message.decode()
print('recv:', message)
I'm trying to send console commands from one machine to another using Python sockets. I want the server to send back the results of the command to the client. If the client types "ls" I want the server to send back the results of running that command. Instead of the expected result, the server just says "action completed: ls". How can I fix this so the server will run the expect commands and return the result?
Server:
import socket
from subprocess import call
def main():
host = '127.0.0.1'
port = 5000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(1)
c, addr = s.accept()
print('Connection established: ' + str(addr))
while True:
try:
data = c.recv(1024).decode('utf-8')
print('sending data: ' + data)
c.send(data.encode('utf-8'))
if data == 'q':
break
except NameError:
error = 'Command does not exist'
c.send(error.encode('utf-8'))
continue
except SyntaxError:
error = 'Command does not exist'
c.send(error.encode('utf-8'))
continue
c.close()
Client:
import socket
from subprocess import call
def main():
host = '127.0.0.1'
port = 5000
s = socket.socket()
s.connect((host, port))
message = str(input('> '))
while message != 'q':
try:
s.send(message.encode('utf-8'))
data = s.recv(1024).decode('utf-8')
print('Action completed: %s' % data)
message = str(input('> '))
except NameError:
print("Command not recognized.")
continue
except SyntaxError:
print("Command not recognized")
continue
I recently built a socket connection in order to communicate with an android device.
I decided to use UDP instead of TCP (which is what you did). For UDP as well as TCP you need a sender and a receiver on both sides of the communication.
The port number that is received in the "addr" variable changes with every connection, so you cannot use it.
What I did, I assigned two different ports one for sending from A to B and the other port to send from B to A.
Here is my server code:
import socket # socket connection
import threading # Multithreading
import time # Timeing
# ----------------------------------------------
# Variables
# ----------------------------------------------
UDPListen2Port = 12345
UDPSend2Port = 123456
Listen2IP = '' # input your local IP here
# ----------------------------------------------
# Threading class
# ----------------------------------------------
class signalProcessingThread(threading.Thread):
def __init__(self, iP, cmdIn):
threading.Thread.__init__(self)
self.iP = iP
self.cmdIn = cmdIn
def run(self):
print("Recv--", self.iP ,"--", self.cmdIn) # Display Thread Info
cmdOut = self.EvalMessage() # Actual signal processing
byteOut = bytes(cmdOut.encode("utf-8")) # Convert Server reply to bytes
sock.sendto(byteOut,(self.iP,UDPSend2Port)) # Send Server Reply to Socket
# ----------------------------------------------
# Initialize Socket
# ----------------------------------------------
sock = socket(AF_INET, SOCK_DGRAM) # -- UDP -- connection
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # in case the port was not properly closed before
sock.bind((Listen2IP,UDPListen2Port)) # bind to the port
# ----------------------------------------------
# Listen to Socket
# ----------------------------------------------
while True:
try: # wait for a connection
data,addr = sock.recvfrom(66507) # number of bytes in the message
msg = data.decode('utf-8')
newThread = signalProcessingThread(addr[0],msg)
newThread.start()
except KeyboardInterrupt:
print('Connection failed')
sock.close()
sock.close()
The client code is quite similar, with the difference that it doesn't necessarily need to run in a thread. Hope I could help.
I have a little problem in my client chat app, basically the app crash if I try to do a function that receive data separately from the one that I use to send them.
Basically, if I have only this function it works:
def send_message (ip_address, port, message):
#Connect to the server
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect((ip_address, port))
#Convert message in bytes-like object
message = message.encode("utf8")
c.send(message)
#Receive data
data = c.recv(88888888888888)
#Decode data from bytes-like object
data = data.decode("utf8")
return data
If I try to do two function, it doesn't work, like this:
def send_message (ip_address, port, message):
#Connect to the server
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect((ip_address, port))
#Convert message in bytes-like object
message = message.encode("utf8")
c.send(message)
def receive_message (ip_address, port, message):
#Connect to the server
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect((ip_address, port))
#Receive data
data = c.recv(88888888888888)
#Decode data from bytes-like object
data = data.decode("utf8")
return data
When I try to call the receive_message function from my GUI the app stop working. Hoping someone can help
EDIT: This is the server code:
import socket
import sys
from threading import Thread
def client_thread(conn, ip, port, MAX_BUFFER_SIZE = 4096):
# the input is in bytes, so decode it
input_from_client_bytes = conn.recv(MAX_BUFFER_SIZE)
# decode input and strip the end of line
input_from_client = input_from_client_bytes.decode("utf8").rstrip()
print("Result of processing is: {}".format(input_from_client))
vysl = res.encode("utf8") # encode the result string
conn.sendall(vysl) # send it to client
conn.close() # close connection
print('Connection ' + ip + ':' + port + " ended")
def start_server():
import socket
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# this is for easy starting/killing the app
soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print('Socket created')
try:
soc.bind(("127.0.0.1", 12345))
print('Socket bind complete')
except socket.error as msg:
import sys
print('Bind failed. Error : ' + str(sys.exc_info()))
sys.exit()
#Start listening on socket
soc.listen(10)
print('Socket now listening')
# for handling task in separate jobs we need threading
from threading import Thread
# this will make an infinite loop needed for
# not reseting server for every client
while True:
conn, addr = soc.accept()
ip, port = str(addr[0]), str(addr[1])
print('Accepting connection from ' + ip + ':' + port)
try:
Thread(target=client_thread, args=(conn, ip, port)).start()
except:
print("Terible error!")
import traceback
traceback.print_exc()
soc.close()
start_server()
You don't show what's on the other end of your connection. I guess it's something like an echo which responds to received messages.
In the first case you open a single connection, first write to it, then read a response.
In the second case you open two separate connections. You write to the first one socket, read from the second one. Is anyone writing on the second socket? I guess not.
Trying to Create Messenger Application within python (cross internet). So far I have successfully been able to send a message to the receiver end and then ping the message back to the user that sent it. However, it does not send the message to all connected users. I think this is because if python is listening for user input the socket cannot receive any data (I might be wrong...).
Below is the client side code:
import socket
host = '**.***.***.***' # Public Ip Hidden
port = 5005 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
b = input("Please enter your message.")
b = b.encode('utf-8')
s.sendall(b)
while True:
data = s.recv(1024)
print('Message Received:', repr(data))
Now below is the server side code:
import socket
import sys
import os
import thread
import threading
from thread import *
from threading import Thread
HOST = '' # Symbolic name meaning all available interfaces
PORT = 5005 # Arbitrary non-privileged port
BUFFER_SIZE = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client = ''
clients = set()
clients_lock = threading.Lock()
print 'Socket created'
#Bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
#Start listening on socket
s.listen(10)
print 'Socket now listening'
#Function for handling connections. This will be used to create threads
def clientthread(conn):
#infinite loop so that function do not terminate and thread do not end.
with clients_lock:
clients.add(client)
while True:
#Receiving from client
data = conn.recv(1024)
if not data:
break
else:
print repr(data)
with clients_lock:
for c in clients:
for d in data:
conn.sendall(data)
print(data.decode("utf-8"))
#came out of loop
conn.close()
#now keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
start_new_thread(clientthread ,(conn,))
s.close()
Any Suggestions would be much appreciated.
I'm writing a very basic chat room in python. Clients connect and any message from a client is relayed to all clients. The problem I'm having is getting the client to listen and send messages at the same time. It seems to only do either one. I've set up a separate listening client and confirmed that the message is received but the listening server cannot send anything.
Currently the client has to send data before getting a response from the server, but I want clients to be able to receive data before sending - otherwise the chat room won't work. I attempted using clientsock.settimeout() and then use recv but it did not solve the issue as it did not move past the input part.
server.py
#!/usr/bin/python
#socket server using threads
import socket, sys, threading
from _thread import *
HOST = 'localhost'
PORT = 2222
lock = threading.Lock()
all_clients = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print ("Socket created")
#bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print ("Bind failed. Error code: " + str(msg[0]) + ' Message ' + msg[1])
sys.exit(0)
print ("Socket bind complete")
#Start listening on socket
s.listen(5)
print ("Socket now listening")
#function for handling connections. This will be used to create threads
def clientthread(conn):
#sending message to connected client
conn.send("Welcome to the server. Type something and hit enter\n".encode('utf-8'))
#infinite loop so that function does not terminate and thread does not end
while True:
#receiving data from client
data = conn.recv(1024)
reply = "OK..." + str(data, "utf-8")
if not data:
break
with lock:
for c in all_clients:
c.sendall(reply.encode('utf-8'))
#came out of loop
conn.close()
#keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
with lock:
all_clients.append(conn)
print ("Connected with " + addr[0] + ":" + str(addr[1]))
#start new thread takes 1st argument as a function name to be run, second
#is the tuple of arguments to the function
start_new_thread(clientthread ,(conn,))
s.close()
client.py
#!/usr/bin/python
import socket, sys
#client to transfer data
def main():
#create tcp stocket
clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#connect the socket to the server open port
server_address = ('localhost', 2222)
print ("connecting to %s port %s" % server_address)
clientsock.connect(server_address)
#receive data
data = clientsock.recv(1024)
print(str(data, "utf-8"))
while 1:
#send data
message = "sean: " + input()
clientsock.send(message.encode('utf-8'))
#look for the response
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = clientsock.recv(1024)
amount_received += len(data)
print ("received %s " % data)
print ("closing socket")
clientsock.close()
main()
new_client.py
#!/usr/bin/python
import socket, sys
from threading import Thread
#client for chat room
def send_msg(sock):
while True:
data = input()
sock.send(data.encode('utf-8'))
def recv_msg(sock):
while True:
stuff = sock.recv(1024)
sock.send(stuff)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 2222)
sock.connect(server_address)
print("Connected to chat")
Thread(target=send_msg, args=(sock,)).start()
Thread(target=recv_msg, args=(sock,)).start()
Create two threads, one for receiving the other for sending. This is the simplest way to do.
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect("address")
def send_msg(sock):
while True:
data = sys.stdin.readline()
sock.send(data)
def recv_msg(sock):
while True:
data, addr = sock.recv(1024)
sys.stdout.write(data)
Thread(target=send_msg, args=(sock,)).start()
Thread(target=recv_msg, args=(sock,)).start()