I'm currently creating an encrypted chat program. Text chat works well. However, I want to implement file transfer, but it doesn't work. My code is trying to work in a way that when one client tries to transfer a file, the server receives it and sends it to another client. When I type '/filetransfer' to transfer file.
Dick: hi
/filetransfer
Sending...
Exception in thread Thread-2:
Traceback (most recent call last):
File "C:\Python\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "C:\Python\lib\threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "c:\Users\USER\Desktop\filetest\client.py", line 198, in sndChat
self.sndFile()
File "c:\Users\USER\Desktop\filetest\client.py", line 233, in sndFile
clientSocket.send(l)
This error occurred. I think the client cannot send the file data.
Also, I would like to apply Diffie-Hellman and AES used for text encryption to file transfer. I spent a lot of time here, but it doesn't work. I desperately need help...
Client.py
def rcvChat(self):
print("\nWelcome to Chatee!")
while True:
try:
message = clientSocket.recv(4096).decode(encodeType)
if self.thred_done:
message=self.aes.decrypt(message)
print(message)
if message == 'filetransfer start':
filereceive_thread = threading.Thread(target=self.rcvChat)
filereceive_thread.join()
#write_thread = threading.Thread(target=self.sndChat)
#write_thread.join()
#self.rcvFile()
break
def sndChat(self):
while True:
message = input('')
if message == '/filetransfer':
message = self.aes.encrypt(message)
clientSocket.send(message)
writefile_thread = threading.Thread(target=self.sndChat)
writefile_thread.start()
self.sndFile()
break
message = self.aes.encrypt(message)
clientSocket.send(message)
def sndFile(self):
print("---File Transfer---")
print("Type a file name...")
filename = 'C:\\Users\\USER\\Desktop\\filetest\\test.txt'
#clientSocket.send(filename.encode(encodeType))
#data_transferred = 0
if not exists(filename):
print("The file doesn't exsit.")
f = open(filename,'rb')
print ('Sending...')
l = f.read(8096)
while (l):
print ('Sending...')
#data_transferred += clientSocket.send(l)
clientSocket.send(l)
l = f.read(8096)
f.close()
print ('Done Sending')
#clientSocket.shutdown(socket.SHUT_WR)
print (clientSocket.recv(8096))
#clientSocket.close
def rcvFile(self):
#filename = clientSocket.recv(1024).decode(encodeType)
#filename = self.aes.decrypt(filename)
filename = 'received.txt'
f = open(filename,'wb')
while True:
print ('Receiving...')
l = clientSocket.recv(8096)
if not l:
print("Fail file transfer")
#sys.exit()
while (l):
print ('Receiving...')
f.write(l)
l = clientSocket.recv(8096)
f.close()
print ('Done Receiving')
Server.py
def handle_client(self,client,client_addr):
client_pvt_key=self.client_keys[client]
client_name=self.clients[client]
print(f"[{client_addr[0]}]-{client_addr[1]} - [{client_name}] - Connected")
print(f"Active Connections - {threading.active_count()-1}")
self.broadcast(f'{client_name} has joined the chat!\n\n')
aes=AESCipher(client_pvt_key)
while True:
try:
msg = aes.decrypt(client.recv(self.header)) #복호화 안하고 바로 브로드캐스트 해도 될듯
if msg == '/filetransfer':
#보낸 사람 제외하고 보내기
self.broadcast('filetransfer start')
thread = threading.Thread(target=self.sndFile, args=(client, ))
thread.start()
thread.join()
elif msg==self.quit_msg:
break
print(f"[{client_addr[0]}]-{client_addr[1]} - [{client_name}]")
msg=f'{client_name}: {msg}'
self.broadcast(msg)
except:
break
client.close()
print(f"[{client_addr[0]}]-{client_addr[1]} - [{client_name}] - quit_msged")
del self.clients[client]
del self.client_keys[client]
self.broadcast(f'{client_name} has left the chat\n')
print(f"Active Connections - {threading.active_count()-2}")
def broadcast(self,msg):
for client in self.clients:
aes=AESCipher(self.client_keys[client])
crypted_msg=aes.encrypt(msg)
client.send(crypted_msg)
def sndFile(self, client):
print("---File Transfer---")
#print("Type a file name...")
client_pvt_key=self.client_keys[client]
aes=AESCipher(client_pvt_key)
#filename = client.recv(1024).decode(self.encodetype)
#self.broadcast('fuck',filename)
while True:
try:
l = client.recv(8096)
print('Rceiving...')
#del self.clients[client]
for client in self.clients:
client.send(l)
#client.send(filename.encode(self.encodetype))
#l = client.recv(8096)
if not l:
print("Fail file transfer")
except:
print('file fail')
break
Related
I have made a file server on python using sockets and threads. The program is supposed to allow the client to upload and download files from the server.
The program works perfectly when only one thread is running, but when both threads are running the server gives an error when trying to upload a file, and when trying to download the program just stops doing anything after the client enters 'Y' to initiate the download.
Here is the code for the client:
import socket
import os
def DownloadFile(s, host, port):
s.connect((host, port))
s.send(str.encode('DNLD'))
filename = input('Filename? ->')
if filename != 'q':
s.send(str.encode(filename))
data = s.recv(2048).decode('UTF-8')
if data[:6] == 'EXISTS':
filesize = data[6:]
message = input('File Exists, ' + str(filesize) + ' Bytes. Download? (Y/N) ->')
if message == 'Y' or message == 'y':
s.send(str.encode('OK'))
f = open('copy of '+filename, 'wb')
data = s.recv(2048)
totalRecv = len(data)
f.write(data)
while totalRecv < int(filesize):
data = s.recv(2048)
totalRecv += len(data)
f.write(data)
print('{}'.format(round((totalRecv/float(filesize))*100),2)+'% Complete')
print('Download Complete!')
s.close()
else:
print('File does not exist')
s.close()
Main()
def UploadFile(s, host, port):
s.connect((host, port))
s.send(str.encode('UPLD'))
filename = input('Filename? ->')
if os.path.isfile(filename):
filesize = os.path.getsize(filename)
filesize = str(filesize)
s.send(str.encode('EXISTS ' + filename))
s.send(str.encode(filesize))
ready = input('Ready to upload. Proceed? (Y/N) ->')
if ready == 'Y' or ready == 'y':
s.send(str.encode('OK'))
with open(filename, 'rb') as f:
bytesToSend = f.read(2048)
s.send(bytesToSend)
while bytesToSend != '':
bytesToSend = f.read(2048)
s.send(bytesToSend)
s.close()
else:
print('File does not exist.')
s.close()
Main()
def Main():
host = '127.0.0.1'
port = 10000
s = socket.socket()
while True:
choice = int(input('Please enter your choice:\n\n1. Upload a file to the server.\n2. Download a file from the server\n3. Quit.\n\n->'))
if choice == 1:
UploadFile(s, host, port)
break
elif choice == 2:
DownloadFile(s, host, port)
break
elif choice == 3:
s.close()
break
else:
print('Please enter a valid choice.')
if __name__ == '__main__':
Main()
And here is the code for the server:
import socket
import threading
import os
def SendFile(name, s):
check = s.recv(2048).decode('UTF-8')
if check == 'DNLD':
filename = s.recv(2048)
if os.path.isfile(filename):
send = os.path.getsize(filename)
send = str(send)
s.send(str.encode('EXISTS ' + send))
userResponse = s.recv(2048)
userResponse = userResponse.decode('UTF-8')
if userResponse[:2] == 'OK':
with open(filename, 'rb') as f:
bytesToSend = f.read(2048)
s.send(bytesToSend)
while bytesToSend != '':
bytesToSend = f.read(2048)
s.send(bytesToSend)
else:
s.send(str.encode('ERR'))
s.close()
def ReceiveFile(name, s):
check = s.recv(2048).decode('UTF-8')
if check == 'UPLD':
data = s.recv(2048).decode('UTF-8')
if data[:6] == 'EXISTS':
filename = data[6:]
data = s.recv(2048).decode('UTF-8')
filesize = data
userResponse = s.recv(2048)
userResponse = userResponse.decode('UTF-8')
if userResponse[:2] == 'OK':
f = open('copy of '+filename, 'wb')
data = s.recv(2048)
totalRecv = len(data)
f.write(data)
while totalRecv < int(filesize):
data = s.recv(2048)
totalRecv += len(data)
f.write(data)
print('Download Complete!')
def Main():
host = '127.0.0.1'
port = 10000
s = socket.socket()
s.bind((host, port))
s.listen(5)
print('Server Started')
while True:
c, addr = s.accept()
print('Client Connected: ' + str(addr))
Send = threading.Thread(target=SendFile, args=('sendThread', c))
Send.start()
Receive = threading.Thread(target=ReceiveFile, args=('retrThread', c))
Receive.start()
s.close()
if __name__ == '__main__':
Main()
If I were to comment out Send.start() or Receive.start() then whatever thread isn't commented out would work perfectly.
Here is the error given in the server when trying to upload a file with both threads running:
Exception in thread Thread-2:
Traceback (most recent call last):
File "C:\Python34\lib\threading.py", line 920, in _bootstrap_inner
self.run()
File "C:\Python34\lib\threading.py", line 868, in run
self._target(*self._args, **self._kwargs)
File "(file location)", line 28, in ReceiveFile
check = s.recv(2048).decode('UTF-8')
OSError: [WinError 10038] An operation was attempted on something that is not a socket
And here is the output in the client when trying to download a file when both threads are running:
Please enter your choice:
1. Upload a file to the server.
2. Download a file from the server
3. Quit.
->2
Filename? ->cat.jpg
File Exists, 10634 Bytes. Download? (Y/N) ->Y
Nothing else happens after entering Y.
If anyone knows what is going wrong I would really appreciate some help.
That's not the way io and threads work. You have here 2 threads competing from the same input data. One will get first packet be it for it or not, and it is likely that one of the following packet will be eaten by the other thread => the first one will never see it!
You can delegate the processing of a conversation to a thread but to a single one that will call a send or receive function once it will have identified the request.
That is not all. TCP is a stream protocol. Packets can be splitted or re-assembled by any piece along the connection (sender, receiver and any gateway). So you should use delimiters to tell the peer that a name or a command if complete. And good practices recommend to pass the size when sending binary data, here again for the peer to know when the data is complete.
Good luck in your journey is the socket world ;-)
I try to make a chat on Python3. Here is my code:
import socket
import threading
print("Server starts working")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("", 57054))
sock.listen(2)
conn, addr = sock.accept()
def get_message():
while True:
data = sock.recv(1024).decode()
if len(data) != 0:
print("Some guy: ", data)
def send_message():
while True:
message = input()
if len(message) != 0:
message = str.encode(message)
sock.send(message)
print("You: ", message)
def run():
get_message_thread = threading.Thread(target=get_message())
send_message_thread = threading.Thread(target=send_message())
get_message_thread.daemon = True
send_message_thread.daemon = True
get_message_thread.start()
send_message_thread.start()
run()
sock.close()
But after the execution and sending a message from other client I get an error message:
Server starts working
Traceback (most recent call last):
File "/home/ptrknvk/Documents/Study/Python/chat/chat.py", line 40, in <module>
run()
File "/home/ptrknvk/Documents/Study/Python/chat/chat.py", line 30, in run
get_message_thread = threading.Thread(target=get_message())
File "/home/ptrknvk/Documents/Study/Python/chat/chat.py", line 15, in get_message
data = sock.recv(1024).decode()
OSError: [Errno 107] Transport endpoint is not connected
Process finished with exit code 1
I've read, that there are some troubles with sock.accept(), but everything's alright here, as I think.
Your program has many flaws. As zondo mentioned, you are incorrectly passing the target. They should be like threading.Thread(target=get_message). Second problem is, you should use conn (and not sock) for sending and receiving data. Third problem is, main thread was blocking at accept call and will wait for the connection. But soon as it accepts a connection, it will exit. From the main thread, you should wait for get_message_thread and send_message_thread. Try the modified code:
import socket
import threading
print("Server starts working")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("", 57054))
sock.listen(2)
conn, addr = sock.accept()
def get_message():
while True:
data = conn.recv(1024).decode()
if len(data) != 0:
print("Some guy: ", data)
def send_message():
while True:
message = input()
if len(message) != 0:
message = str.encode(message)
conn.send(message)
print("You: ", message)
def run():
get_message_thread = threading.Thread(target=get_message)
send_message_thread = threading.Thread(target=send_message)
get_message_thread.daemon = True
send_message_thread.daemon = True
get_message_thread.start()
send_message_thread.start()
get_message_thread.join()
send_message_thread.join()
run()
sock.close()
I'm attempting to add an irc client to a django web application I'm working on. I'd like the server side code for the irc communication to use python and connect through the sockets library. I'll then use gevent-socketio to send and receive data from the irc channel to the client side in the browser. So far I have a very basic gevent-socketio server and client that can be used for realtime broadcasting amongst multiple clients, however, when I start to connect clients to IRC they connect to the IRC server successfully using a nick passed from the client, but then it appears that this is ongoing keepalive/listening process is blocking be from sending any messages from the client.
Python IRC code
import socket
class pycli:
def __init__(self,user):
self.nick = user
self.chan = "#testchannel"
self.owner = "Bluebot"
self.sock = socket.socket()
print "irc conn"
def send_msg(self,message):
self.sock.send("PRIVMSG " + self.chan + " : " + message + "\r\n")
## misc setup
def keep_alive(self):
self.sock.connect(("irc.freenode.net",6667))
self.sock.send("USER " + self.nick + " 0 * :" + self.owner + "\r\n")
self.sock.send("NICK " + self.nick + "\r\n")
while 1:
## keep checking for data
data = self.sock.recv(512)
datalen = len(data.split(" "))
sender = ""
msg_type = ""
msg_rcpt = ""
message = ""
###----------------------------------------------
## reply to keep alive pings
if data[0:4] == "PING":
self.sock.send(data.replace("PING", "PONG"))
if data[0]!=':':
continue
if data.split(" ")[1] == "001":
self.sock.send("MODE " + self.nick + " +B\r\n")
self.sock.send("JOIN " + self.chan + "\r\n")
###-----------------------------------------------
##split and assign data parts
## parse out the actual sender
send_data = data.split(" ")[0]
send_data = send_data[1:]
sender = send_data.split('!')[0]
## mode
msg_type = data.split(" ")[1]
## if it exists get the recipient (room or private)
if datalen > 2:
msg_rcpt = data.split(" ")[2]
## get the actual message body
if datalen > 3:
message = (" ".join(data.split(" ")[3:])).lower()[1:]
print data
I know this functionality is super basic, but I can expand on it once I get it working through the client.
The relevant parts of my server code basically looks like:
def on_login(self, nick):
if self.nick:
self._broadcast('exit', self.nick)
self.nick = nick
self._broadcast('enter', nick)
self.emit('users',
[ ns.nick
for ns in self._registry.values()
if ns.nick is not None ])
t = threading.Thread(target=self.make_start_irc(nick),daemon=True)
t.start()
def on_chat(self, message):
if self.nick:
self._broadcast('chat', dict(u=self.nick, m=message))
self._irc_nicks[self.nick].send_msg("this is a test")
else:
self.emit('chat', dict(u='SYSTEM', m='You must first login'))
def make_start_irc(self,nick):
if nick not in self._irc_nicks.values():
self._irc_nicks[nick] = pycli.pycli(nick)
print self._irc_nicks
self._irc_nicks[nick].keep_alive()
def _broadcast(self, event, message):
for s in self._registry.values():
s.emit(event, message)
def chat(environ, start_response):
if environ['PATH_INFO'].startswith('/socket.io'):
return socketio_manage(environ, { '/chat': ChatNamespace })
else:
return serve_file(environ, start_response)
def serve_file(environ, start_response):
path = os.path.normpath(
os.path.join(public, environ['PATH_INFO'].lstrip('/')))
assert path.startswith(public), path
if os.path.exists(path):
start_response('200 OK', [('Content-Type', 'text/html')])
with open(path) as fp:
while True:
chunk = fp.read(4096)
if not chunk: break
yield chunk
else:
start_response('404 NOT FOUND', [])
yield 'File not found'
if __name__ == "__main__":
from gevent import monkey
monkey.patch_all()
sio_server = SocketIOServer(
('', 8080), chat,
policy_server=False)
t2 = threading.Thread(target=sio_server.serve_forever())
t2.start()
When I eventually give up and use ctrl-C, I see the following stacktrace which leads me to believe something about the way I'm threading is blocking.
Traceback (most recent call last):
File "socketio_test.py", line 92, in <module>
t2 = threading.Thread(target=sio_server.serve_forever())
File "/Users/andrewscott/Desktop/wham/pycli/wham/lib/python2.7/site-packages/gevent/baseserver.py", line 284, in serve_forever
self._stop_event.wait()
File "/Users/andrewscott/Desktop/wham/pycli/wham/lib/python2.7/site-packages/gevent/event.py", line 77, in wait
result = self.hub.switch()
File "/Users/andrewscott/Desktop/wham/pycli/wham/lib/python2.7/site-packages/gevent/hub.py", line 338, in switch
return greenlet.switch(self)
KeyboardInterrupt
If anyone has any idea how I can change the irc process to be non-blocking, or any general suggestions they'd be greatly appreciated.
You should remove the call:
t2 = threading.Thread(target=sio_server.serve_forever())
And properly pass the method:
t2 = threading.Thread(target=sio_server.serve_forever)
I want to start a project to learn python, and I chose to write a simple web proxy.
In some case, some thread seems get a null request, and python rasie exception:
first_line: GET http://racket-lang.org/ HTTP/1.1
Connect to: racket-lang.org 80
first_line:
Exception in thread Thread-2:
Traceback (most recent call last):
File "C:\Python27\lib\threading.py", line 551, in __bootstrap_inner
self.run()
File "C:\Python27\lib\threading.py", line 504, in run
self.__target(*self.__args, **self.__kwargs)
File "fakespider.py", line 37, in proxy
url = first_line.split(' ')[1]
IndexError: list index out of range
first_line: first_line: GET http://racket-lang.org/plt.css HTTP/1.1GET http://racket-lang.org/more.css HTTP/1.1
Connect to:Connect to: racket-lang.orgracket-lang.org 8080
My code was simple.
I don't know what's going on, any help would be appreciated:)
from threading import Thread
from time import time, sleep
import socket
import sys
RECV_BUFFER = 8192
DEBUG = True
def recv_timeout(socks, timeout = 2):
socks.setblocking(0);
total_data = []
data = ''
begin = time()
while True:
if total_data and time() - begin > timeout:
break
elif time() - begin > timeout * 2:
break
try:
data = socks.recv(RECV_BUFFER)
if data:
total_data.append(data)
begin = time()
else:
sleep(0.1)
except:
pass
return ''.join(total_data)
def proxy(conn, client_addr):
request = recv_timeout(conn)
first_line = request.split('\r\n')[0]
if (DEBUG):
print "first_line: ", first_line
url = first_line.split(' ')[1]
http_pos = url.find("://")
if (http_pos == -1):
temp = url
else:
temp = url[(http_pos + 3):]
port_pos = temp.find(":")
host_pos = temp.find("/")
if host_pos == -1:
host_pos = len(temp)
host = ""
if (port_pos == -1 or host_pos < port_pos):
port = 80
host = temp[:host_pos]
else:
port = int((temp[(port_pos + 1):])[:host_pos - port_pos - 1])
host = temp[:port_pos]
print "Connect to:", host, port
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send(request)
data = recv_timeout(s)
if len(data) > 0:
conn.send(data)
s.close()
conn.close()
except socket.error, (value, message):
if s:
s.close()
if conn:
conn.close()
print "Runtime error:", message
sys.exit(1)
def main():
if len(sys.argv) < 2:
print "Usage: python fakespider.py <port>"
return sys.stdout
host = "" #blank for localhost
port = int(sys.argv[1])
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(50)
except socket.error, (value, message):
if s:
s.close()
print "Could not open socket:", message
sys.exit(1)
while 1:
conn, client_addr = s.accept()
t = Thread(target=proxy, args=(conn, client_addr))
t.start()
s.close()
if __name__ == "__main__":
main()
The stack trace you see says everything:
url = first_line.split(' ')[1]
IndexError: list index out of range
Apparently the result of splitting variable first_line is not a list having more than one element, as you assumed. So it contains something different than you expected. To see what it actually contains just print it out:
print first_line
or use a debugger.
I want to tail multiple files concurrently and push the logs to scribe.
I am reading the files from a Config file then I want to tail each file and send the logs to scribe.
What I have tried is sends log for only the first file and doesn't for the others.
I want to run the tailing concurrently for each file and send the logs for each one of them at same time.
for l in Config.items('files'):
print l[0]
print l[1]
filename = l[1]
file = open(filename,'r')
st_results = os.stat(l[1])
st_size = st_results[6]
file.seek(st_size)
while 1:
where = file.tell()
line = file.readline()
if not line:
time.sleep(1)
file.seek(where)
else:
print line, # already has newline
category=l[0]
message=line
log_entry = scribe.LogEntry(category, message)
socket = TSocket.TSocket(host='localhost', port=1463)
transport = TTransport.TFramedTransport(socket)
protocol = TBinaryProtocol.TBinaryProtocol(trans=transport, strictRead=False, strictWrite=False)
client = scribe.Client(iprot=protocol, oprot=protocol)
transport.open()
result = client.Log(messages=[log_entry])
transport.close()
Try something like this (Inspired by this)
import threading
def monitor_file(l):
print l[0]
print l[1]
filename = l[1]
file = open(filename,'r')
st_results = os.stat(l[1])
st_size = st_results[6]
file.seek(st_size)
while 1:
where = file.tell()
line = file.readline()
if not line:
time.sleep(1)
file.seek(where)
else:
print line, # already has newline
category=l[0]
message=line
log_entry = scribe.LogEntry(category, message)
socket = TSocket.TSocket(host='localhost', port=1463)
transport = TTransport.TFramedTransport(socket)
protocol = TBinaryProtocol.TBinaryProtocol(trans=transport, strictRead=False, strictWrite=False)
client = scribe.Client(iprot=protocol, oprot=protocol)
transport.open()
result = client.Log(messages=[log_entry])
transport.close()
for l in Config.items('files'):
thread = threading.Thread(target=monitor_file, args=(l))
A different implementation of #Pengman's idea:
#!/usr/bin/env python
import os
import time
from threading import Thread
def follow(filename):
with open(filename) as file:
file.seek(0, os.SEEK_END) # goto EOF
while True:
for line in iter(file.readline, ''):
yield line
time.sleep(1)
def logtail(category, filename):
print category
print filename
for line in follow(filename):
print line,
log_entry(category, line)
for args in Config.items('files'):
Thread(target=logtail, args=args).start()
Where log_entry() is a copy of the code from the question:
def log_entry(category, message):
entry = scribe.LogEntry(category, message)
socket = TSocket.TSocket(host='localhost', port=1463)
transport = TTransport.TFramedTransport(socket)
protocol = TBinaryProtocol.TBinaryProtocol(trans=transport,strictRead=False,
strictWrite=False)
client = scribe.Client(iprot=protocol, oprot=protocol)
transport.open()
result = client.Log(messages=[entry])
transport.close()
follow() could be implemented using FS monitoring tools, see tail -f in python with no time.sleep.