I started to code in python with sockets and I have a little problem for my chat script.
Server script
import pickle, socket, struct, sys, threading
SERVERADDRESS = ("localhost", 6030)
class helloChatServer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.__server = socket.socket()
self.users = []
try:
self.__server.bind(SERVERADDRESS)
except socket.error:
print('Bind failed {}'.format(socket.error))
self.__server.listen(10)
def exit(self):
self.__server.close()
def run(self):
print( "Listening... {}".format(SERVERADDRESS))
while True:
client, addr = self.__server.accept()
try:
threading.Thread(target=self._handle, args=(client, addr)).start()
except OSError:
print('Error during processing the message')
def _handle(self, client, addr):
print('Client connected with {}:{}'.format(addr[0], str(addr[1])))
self.users.append(addr)
while True:
data = client.recv(1024)
print(data)
client.send(data)
client.close()
if __name__ == '__main__':
helloChatServer().run()
Client script
import pickle, socket, struct, sys, threading
SERVERADDRESS = (socket.gethostname(), 6050)
class helloChatClient():
def __init__(self, host='localhost', port=5000, pseudo="Visitor"):
self.__socket = socket.socket()
self.__socket.bind((host, port))
self.__pseudo = pseudo
print('Listening on {}:{}'.format(host, port))
def run(self):
handlers = {
'/exit': self._exit,
'/quit': self._quit,
'/join': self._join,
'/send': self._send
}
self.__running = True
self.__address = None
threading.Thread(target=self._receive).start()
while self.__running:
line = sys.stdin.readline().rstrip() + ' '
# Extract the command and the param
command = line[:line.index(' ')]
param = line[line.index(' ')+1:].rstrip()
# Call the command handler
if command in handlers:
try:
handlers[command]() if param == '' else handlers[command](param)
except:
print("Error during the execution of the message")
else:
print('Command inconnue:', command)
def _exit(self):
self.__running = False
self.__address = None
self.__socket.close()
def _quit(self):
self.__address = None
def _join(self, param):
if self.__pseudo == "Visitor":
self.__pseudo = input("Choose a username: ")
tokens = param.split(' ')
if len(tokens) == 2:
try:
self.__address = (tokens[0], int(tokens[1]))
self.__socket.connect(self.__address)
print('~~~~~~~~~~~~~~~~~~~~~~~~~~')
print('Connected at {}:{}'.format(*self.__address))
print('~~~~~~~~~~~~~~~~~~~~~~~~~~')
except OSError:
print("Error during the sending of the message")
self.__socket.send(self.__pseudo.encode())
def _send(self, param):
if self.__address is not None:
try:
message = param.encode()
totalsent = 0
while totalsent < len(message):
sent = self.__socket.send(message[totalsent:])
totalsent += sent
print(self.__socket.recv(1024).decode())
except OSError:
print('Error during the reception of the message')
def _receive(self):
while self.__running:
try:
data = self.__socket.recv(1024).decode()
print(data)
except socket.timeout:
pass
except OSError:
return
if __name__ == '__main__':
if len(sys.argv) == 4:
helloChatClient(sys.argv[1], int(sys.argv[2]), sys.argv[3]).run()
else:
helloChatClient().run()
Well when I run the script on the terminal, I see this.
Server
MacBook-Pro-de-Saikou:labo2 saikouah$ python3.4 helloChatServer.py
En écoute sur... ('MacBook-Pro-de-Saikou.local', 6030)
Client connected with 127.0.0.1:5004
Il y a actuellement 1 connecté
b'bluebeel'
b'hello'
Client
MacBook-Pro-de-Saikou:labo2 saikouah$ python3.4 helloChatClient.py localhost 5004 bluebeel
Écoute sur localhost:5004
/join MacBook-Pro-de-Saikou.local 6030
~~~~~~~~~~~~~~~~~~~~~~~~~~
Connecté à MacBook-Pro-de-Saikou.local:6030
~~~~~~~~~~~~~~~~~~~~~~~~~~
/send hello
bluebeel
On the client terminal he doesn't print me hello but bluebeel. I made several test and he took me every time the previous one message. Looks like he is late.
Someone can help me? :)
PROBLEM ANALYSIS
Your code fails in _receive function:
data = self.__socket.recv(1024).decode()
This line throws OSError because you try to call .recv before connecting to the server. Thus the exception handler is fired and the function exits. So what happens is that after calling
threading.Thread(target=self._receive).start()
function _receive exits before you call /join. So watch what happens
You call /join.
bluebeel is send to the server
Server receives it and sends it back to the client
But _receive function is no longer there. So the message is "stacked" on the socket (it will wait for next .recv() call)
You call /send hello
Server receives hello and sends it back
Client calls print(self.__socket.recv(1024).decode()) in _send method
But .recv retrieves the first message that is stacked on the socket. In that case it is not hello, it is bluebeel.
Now this schema continues to work. You send message, server pings it back but there's always 1 message in front of the received one. The "late" message.
SOLUTION
One way of solving this issue is to call
threading.Thread(target=self._receive).start()
in ._join method after .connect. Remember to remove print(self.__socket.recv(1024).decode()) from _send method, otherwise it will block stdin.
Of course you will have problems when issuing multiple /join commands. To properly address that you would have to keep track of _receive thread and kill it at the begining of ._join method. This however is beyond the scope of this question IMHO.
SIDE NOTE
Don't ever handle exceptions like you did. This is wrong:
try:
data = self.__socket.recv(1024).decode()
print(data)
except socket.timeout:
pass
except OSError:
return
At least do this:
import traceback
try:
data = self.__socket.recv(1024).decode()
print(data)
except socket.timeout:
traceback.print_exc()
except OSError:
traceback.print_exc()
return
Related
I'm trying to create an online code to a game I'm making. Obviously, running this code gives an error. The error is [WinError 10053] An established connection was aborted by the software in your host machine.
Here's my code:
SERVER
from _thread import *
import sys
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
server = 'localhost'
port = 5555
server_ip = socket.gethostbyname(server)
try:
s.bind((server, port))
except socket.error as e:
print(str(e))
s.listen(2)
print("Currently waiting for other users...")
currentId = "0"
pos = ["0:50,50", "1:100,100"]
def threaded_client(conn):
global currentId, pos
conn.send(str.encode(currentId))
currentId = "1"
reply = ''
while True:
try:
data = conn.recv(2048)
reply = data.decode('utf-8')
if not data:
conn.send(str.encode("Goodbye"))
break
else:
print("Recieved: " + reply)
arr = reply.split(":")
id = int(arr[0])
pos[id] = reply
if id == 0: nid = 1
if id == 1: nid = 0
reply = pos[nid][:]
print("Sending: " + reply)
conn.sendall(str.encode(reply))
except:
break
print("Connection Closed")
conn.close()
while True:
conn, addr = s.accept()
start_new_thread(threaded_client, (conn,))
CLIENT
import time
class Network:
def __init__(self):
randomvar = "."
while True:
try:
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.host = "localhost" # For this to work on your machine this must be equal to the ipv4 address of the machine running the server
# You can find this address by typing ipconfig in CMD and copying the ipv4 address. Again this must be the servers
# ipv4 address. This feild will be the same for all your clients.
self.port = 5555
self.addr = (self.host, self.port)
self.id = self.connect()
break
except ConnectionRefusedError:
if randomvar != "Waiting for server...":
print("Waiting for server...")
randomvar = "Waiting for server..."
def getNumber(self):
pass
def connect(self):
self.client.connect(self.addr)
return self.client.recv(2048).decode()
def send(self, data):
"""
:param data: str
:return: str
"""
try:
self.client.send(str.encode(data))
reply = self.client.recv(2048).decode()
return reply
except socket.error as e:
return str(e)
n = Network()
print(n.send("Host"))
print(n.send("hello"))
On the server, the only things it receives Host, but not hello. That's where I get the error, but It won't tell me which line it is.
Any help?
You are ignoring the exception. Instead, print it out to get an idea of what is wrong:
Traceback (most recent call last):
File "D:\temp\python\server.py", line 39, in threaded_client
id = int(arr[0])
ValueError: invalid literal for int() with base 10: 'Host'
This leads to this line:
id = int(arr[0])
It looks like the server is expecting the messages to be in the form of id:msg but the client is not sending that. It is just sending the message without an id. You can check this in the server.
arr = reply.split(":")
if len(arr) != 2 or !arr[0].isdigit():
# Handle error....
When closing the connection, you are likely forgetting to close both sides.
I was able to modify your code to fit the scenario from this post which explains the root cause of [WinError 10053] An established connection was aborted by the software in your host machine, which lies in the WSAECONNABORTED error from WinSock, the windows sockets api
I made a more detailed answer about this on this SO post.
I am trying to check if data is available on one port. If this it is avaiable then a message "yes" should be sent to another port and "no" if there is no data.
A client is connecting to that port where "yes" or "no" is coming. I run the script and every thing looked fine. But after one hour I got the error:
Runtime error can not start new thread. Exception in Thread 11:
Traceback< most recent call last: file threading.py line 914 in boot strap-inner.
I am new to python and I really do not understand what is going on. My code contains many threads as I am checking data from 10 ports and sending "yes" or "no" message to other 10 ports.
Here is a part of my code for 1 port:
import time
import socket
import threading
from threading import Thread
import select
#-----------------------------------Server --------------------------
s = socket.socket(socket.AF_INET) #Socket
h = '127.0.0.1' #Host where data coming from
p = 14201 #Port
halarm = "127.0.0.1" # A port will be opened to send availabilty status
palarm = 14202 # Port
def Server ():
while True:
try:
time.sleep(0.1)
s.connect((h, p))
except socket.error:
pass
#-----------------------------------Server/Client -------------------------------
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind((halarm, palarm)) # Bind to the Port where
sock.listen(1)
def func(conn): # Server-Client Function
while True:
try:
global s
Timeout = select.select([s], [], [], 5)# Timeout in seconds
connected = True
while True:
try:
if Timeout[0]:
conn.send(bytes("yes", "utf-8"))
time.sleep(3)
else:
conn.send(bytes("no", "utf-8"))
time.sleep(3)
newConnection= False
while not newConnection:
try:
s = socket.socket(socket.AF_INET)
s.connect((h, p))
Timeout = select.select([s], [], [], 5)# Timeout in seconds
newConnection= True
except socket.error:
conn.send(bytes("Port is closed", "utf-8"))
time.sleep(3)
pass
except socket.error:
pass
except:
pass
def connThread():
while True:
conn, addr = sock.accept()
time.sleep(0.1)
Thread(target = func, args=(conn,)).start()
if __name__ == '__main__':
Thread(target = Server).start()
Thread(target = connThread).start()
How can I solve this problem ? I appreciate all your help.
Well, I'm trying to make a simple Network TCP chatting program to dive deeper in python, threading and networking. The program worked but with just one user, I looked this up, I found that I need threading to make the server accept more than one user. I threaded the server but now when you connect the second user it disconnect the first one. Source code may not be that good..
#!/usr/bin/python
import socket, sys, threading
from time import sleep
# Global Stuff
localhost = socket.gethostbyname(socket.gethostname())
#localhost = '192.168.x.x'
serverPort = 5003
buffer = 1024 #Bytes
backlog = 5
userThread= []
count = 0
class server(object):
''' Constructor to Establish Bind server once an object made'''
def __init__(self, localhost, serverPort): # Connect Tcp
global backlog, count
self.servSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.servSock.bind((localhost, serverPort))# bind((host,Port))
self.servSock.listen(backlog)
print count
except Exception, e:
print "[Bind ]", e
sys.exit()
def accept(self):
global userThread, conn, addr, count
"""
- PROBLEM IS IN HERE SOMEWHERE SERVER DOESN'T ADD THE OTHER CLIENT EXCEPT ONCE.
- THREAD DOEN'T KEEP THE CLIENT.
- THE SECOND CLIENT FREEZES WHILE SENDING THE VERY FIRST MESSAGE TILL THE FIRST
CLIENT SEND A MESSAGE THEN IT CAN SEND MESSAGES AND THE FIRST CLIENT CAN'T SEND SHIT.
"""
count+=1
while True:
print count
self.conn, self.addr = self.servSock.accept()
conn = self.conn
print("This is a connection: ", conn)
#acceptThread = threading.start_new_thread(target=serverObj.accept, args=(conn))
#addr = self.addr
print "[Listening..]"
if(self.addr not in userThread):
userThread.append(self.addr)
print "Client's added Successfully"
else:
pass
def redirect(self):
global buffer, userThread, conn, count
count+=1
while True:
try:
print "Redirecting " + str(count)
self.data = conn.recv(buffer)
if self.data:
for user in userThread:
#conn.send(b'Recieved by server!\n')
conn.sendto("Sent!\n"+self.data+"\n", user)
print "Server: Data sent[" +self.data+"] to ["+str(user)+"]"
else:
self.data = conn.recv(buffer)
print "No dataa found"
except Exception, e:
print "[Redirect ] ",e
sleep(7)
print "OUT"# testing if it's getting out this infinite loop.
def exit(self):
self.server.close()
def main():
global localhost, serverPort, conn
try:
serverObj = server(localhost, serverPort)
print("[+] Server is UP!")
except Exception, e:
print "[Main ] ",e
exit()
acceptThread = threading.Thread(name = "Accepting Connections", target=serverObj.accept)
redirThread = threading.Thread(name = "Redirecting Data", target=serverObj.redirect)
acceptThread.start()
redirThread.start()
print userThread
main()
######################################### Client ##########################################
#!/usr/bin/python
# This is client file
"""
http://eli.thegreenplace.net/2011/05/18/code-sample-socket-client-thread-in-python
https://docs.python.org/2/library/threading.html
"""
import socket
import threading
from time import sleep
# Client Info
#clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#localhost = '192.168.x.x'
# Global Stuff
serverIP = socket.gethostbyname(socket.gethostname())
#serverIP = '192.168.x.x'
serverPort, MsgSendError, MsgSendSucc, clientPort, data, buffer =\
5003, False, True, 12345, '',1024 #Bytes
class client(object):
global MsgSendError, MsgSendSucc, buffer, data
''' Constructor to Establish Connection once client is up'''
def __init__(self, serverIP, serverPort): # Connect Tcp
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.sock.connect((serverIP, serverPort))
except Exception, e:
return "[Connecting to Server]", e
def send(self, data):
try:
self.sock.send(data) # covnert it from string into byte streams to be in proper format.
#print str(data)
return MsgSendSucc
except:
return MsgSendError
def receive2(self):
try:
data = self.sock.recv(buffer)
#print "Function: Receive2."# testing
#print(str(data))# testing
#print "Received!"# testing
return str(data)
except Exception, e:
return "[In receive2]", e
def main():
global serverIP, serverPort, data#, sock
clientObj = client(serverIP, serverPort)
alias = raw_input("Your Name USER! ")
sentData = ''
while sentData is not 'Quit':
sentData = raw_input("Data>> ")
data = alias + ": "+sentData
if clientObj.send(data) == MsgSendSucc:
#print "Sent!"
#print "Fetching..\n"# testing
print(clientObj.receive2())
# testing
main()
I have a Client and a Server and I need to transfer some files using sockets. I can send small messages, but when I try to send a File, the problems begins...
client.py:
from socket import *
from threading import Thread
import sys
import hashlib
class Client(object):
ASK_LIST_FILES = "#001" # 001 is the requisition code to list
# all the files
ASK_SPECIFIC_FILE = "#002" # 002 is the requisition code to a
# specific file
SEND_FILE = "#003" # 003 is the requisition code to send one
# file
AUTHENTICATION = "#004" # 004 is the requisition code to user
# authentication
listOfFiles = []
def __init__(self):
try:
self.clientSocket = socket(AF_INET, SOCK_STREAM)
except (error):
print("Failed to create a Socket.")
sys.exit()
def connect(self, addr):
try:
self.clientSocket.connect(addr)
except (error):
print("Failed to connect.")
sys.exit()
print(self.clientSocket.recv(1024).decode())
def closeConnection(self):
self.clientSocket.close()
def _askFileList(self):
try:
data = Client.ASK_LIST_FILES
self.clientSocket.sendall(data.encode())
# self._recvFileList()
except (error):
print("Failed asking for the list of files.")
self.closeConnection()
sys.exit()
thread = Thread(target = self._recvFileList)
thread.start()
def _recvFileList(self):
print("Waiting for the list...")
self.listOfFiles = []
while len(self.listOfFiles) == 0:
data = self.clientSocket.recv(1024).decode()
if (data):
self.listOfFiles = data.split(',')
if(len(self.listOfFiles) > 0):
print (self.listOfFiles)
def _askForFile(self, fileIndex):
fileIndex = fileIndex - 1
try:
data = Client.ASK_SPECIFIC_FILE + "#" + str(fileIndex)
self.clientSocket.sendall(data.encode())
except(error):
print("Failed to ask for an specific file.")
self.closeConnection()
sys.exit()
self._downloadFile(fileIndex)
def _downloadFile(self, fileIndex):
print("Starting receiving file")
f = open("_" + self.listOfFiles[fileIndex], "wb+")
read = self.clientSocket.recv(1024)
# print(read)
# f.close
while len(read) > 0:
print(read)
f.write(read)
f.flush()
read = self.clientSocket.recv(1024)
f.flush()
f.close()
self.closeConnection()
server.py
from socket import *
from threading import Thread
import sys
import glob
class Server(object):
def __init__(self):
try:
self.serverSocket = socket(AF_INET, SOCK_STREAM)
except (error):
print("Failed to create a Socket.")
sys.exit()
def connect(self, addr):
try:
self.serverSocket.bind(addr)
except (error):
print ("Failed on binding.")
sys.exit()
def closeConnection(self):
self.serverSocket.close()
def waitClients(self, num):
while True:
print("Waiting for clients...")
self.serverSocket.listen(num)
conn, addr = self.serverSocket.accept()
print("New client found...")
thread = Thread(target = self.clientThread, args = (conn,))
thread.start()
def clientThread(self, conn):
WELCOME_MSG = "Welcome to the server"
conn.send(WELCOME_MSG.encode())
while True:
data = conn.recv(2024).decode()
if(data):
# print(data)
# reply = 'OK: ' + data
# conn.sendall(reply.encode())
if(data == "#001"):
listOfFiles = self.getFileList()
strListOfFiles = ','.join(listOfFiles)
self._sendFileList(strListOfFiles, conn)
else:
dataCode = data.split('#')
print(dataCode)
if(dataCode[1] == "002"):
print("Asking for file")
self._sendFile(int(dataCode[2]), conn)
if(dataCode[1] == "003"):
print("Pedido de login")
if self._authentication(dataCode[2]):
conn.send("OK".encode())
# self._recvFile(conn)
else:
conn.send("FAILED".encode())
def _sendFile(self, fileIndex, conn):
listOfFiles = self.getFileList()
print(fileIndex)
print(listOfFiles[fileIndex])
f = open(listOfFiles[fileIndex], "rb")
read = f.read(1024)
while len(read) > 0:
conn.send(read)
read = f.read(1024)
f.close()
def _sendFileList(self, strList, conn):
try:
conn.sendall(strList.encode())
except (error):
print("Failed to send list of files.")
def getFileList(self):
return glob.glob("files/*")
When I try to get a file from my server, I can transfer everything but the connection never ends. What is going on with my code?
First, you are doing here the most common error using TCP: assume all data sent in a single send() will be got identically in a single recv(). This is untrue for TCP, because it is an octet stream, not a message stream. Your code will work only under ideal (lab) conditions and could mysteriously fail in a real world usage. You should either explicitly invent message boundaries in TCP streams, or switch e.g. to SCTP. The latter is available now almost everywhere and keeps message boundaries across a network connection.
The second your error is directly connected to the first one. When sending file, you don't provide any explicit mark that file has been finished. So, clients waits forever. You might try to close server connection to show that file is finished, but in that case client won't be able to distinguish real file end and connection loss; moreover, the connection won't be reusable for further commands. You would select one of the following ways:
Prefix a file contents with its length. In this case, client will know how many bytes shall be received for the file.
Send file contents as a chunk sequence, prefixing each chunk with its length (only for TCP) and with mark whether this chunk is last (for both transports). Alternatively, a special mark "EOF" can be sent without data.
Similarly, control messages and their responses shall be provided with either length prefix or a terminator which can't appear inside such message.
When you finish developing this, you would look at FTP and HTTP; both addresses all issues I described here but in principally different ways.
I'm writing interprocess communication using localhost sockets in Python 3.2 and testing it on Windows. Here is some test code with a server and a client, sending messages to each other. Strangely, it fails randomly with the RuntimeError error, raised in the receive function, somewhere around the 5th or 10th connection.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket
import pickle
import time
import logging
from multiprocessing import Process
def receive(conn):
def ensure_receive(length):
parts = []
received = 0
while received < length:
chunk = conn.recv(length - received)
if not chunk:
raise RuntimeError("Connection broken")
parts.append(chunk)
received += len(chunk)
return b''.join(parts)
lengthString = ensure_receive(8)
serialized = ensure_receive(int(lengthString))
return pickle.loads(serialized)
def send(conn, message):
def ensure_send(message):
sent = 0
while sent < len(message):
sent += conn.send(message[sent:])
# logging.warning("Now sending")
serialized = pickle.dumps(message, 1)
messageLength = len(serialized)
ensure_send("{:8}".format(messageLength).encode('Latin-1'))
ensure_send(serialized)
def client_function(clientLimit):
for index in range(1, clientLimit + 1):
print ("Client", index)
try:
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.connect(('localhost', 12333))
send(conn, list(range(100000)))
message = receive(conn)
send(conn, list(range(100)))
# time.sleep(0.01)
conn.shutdown(socket.SHUT_WR)
conn.close()
except Exception:
logging.exception("Socket error in client")
def server_function(clientLimit):
newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
newSocket.bind(('localhost', 12333))
newSocket.listen(16)
for _ in range(clientLimit):
(conn, address) = newSocket.accept()
time.sleep(0.01)
message = receive(conn)
send(conn, list(range(10)))
message = receive(conn)
conn.shutdown(socket.SHUT_WR)
conn.close()
def test(clientLimit):
server = Process(target = server_function, args = (clientLimit,))
server.start()
time.sleep(1)
client = Process(target = client_function, args = (clientLimit,))
client.start()
client.join()
server.join()
if __name__ == "__main__":
test(100)
However, there are no errors if I uncomment time.sleep(0.01) in client_function, or if I change message order a bit.
Is there a way to make it work, without putting in random waits, and allowing for arbitrary protocols?
It is because of conn.shutdown(socket.SHUT_WR) in your server_function. What you need is socket.SHUT_RD, or better yet, get rid of the shutdown() call at all.