I have a server-client setup that works as follows:
The client connects to the server.
The client sends the server a 64-byte message telling the server how much data to read
The server reads that many bytes of data, responds, and the process repeats.
When the client is finished, it sends the server a null message
The server sees that the message length is 0 and closes the connection.
This seems to work fine for the first pass. After the server responds though, it doesn't wait for the client to send more data. Instead the server immediately reads 64 bytes. Since the client hasn't responded, the length of the message is 0 and the connection is closed.
I'm unsure why the server is not pausing until the client sends more data.
Here is the server loop:
self.__stop = False
while not self.__stop:
if self.client_sock:
# Check if the client is still connected and if data is available
try:
rdy_read, rdy_write, sock_err = select.select(
[self.client_sock, ], [self.client_sock, ], [], 5)
except select.error as err:
self.stop()
return
if len(rdy_read) > 0:
# msg length will be sent as bytes
read_data = self.client_sock.recv(64)
# Check if the socket has been closed
if read_data == 0:
self.stop()
else:
msg_length = int(read_data)
msg = self.client_sock.recv(msg_length)
response = f"{[12, 15, 66]}\n"
msg_size = padded_size_of_msg(response)
self.client_sock.send(msg_size)
self.client_sock.send(f"{response}".encode('utf-8'))
else:
print(
f"[THREAD {self.number}] No client connected.")
self.stop()
self.close()
The function padded_size_of_msg() is to calculate the length of the message, pad that number to be 64-bytes, then send that to the client:
def padded_size_of_msg(msg):
msg_length = len(msg)
send_length = str(msg_length).encode('utf-8')
send_length += b' ' * (64- len(send_length))
return send_length
The complete class declaration is below:
class ServerSocketThread(Thread):
def __init__(self, client_sock, client_addr, number):
Thread.__init__(self)
self.client_sock = client_sock
self.client_addr = client_addr
self.number = number
def run(self):
self.__stop = False
while not self.__stop:
if self.client_sock:
# Check if the client is still connected and if data is available
try:
rdy_read, rdy_write, sock_err = select.select(
[self.client_sock, ], [self.client_sock, ], [], 5)
except select.error as err:
print(
f"[THREAD {self.number}] Select() failed on socket with {self.client_addr}")
self.stop()
return
if len(rdy_read) > 0:
# msg length will be sent as bytes
read_data = self.client_sock.recv(64)
# Check if the socket has been closed
if read_data == 0:
print(
f"[THREAD {self.number}] {self.client_addr} closed the socket")
self.stop()
else:
msg_length = int(read_data)
# Client will send msg as bytes. No need to decode to str
msg = self.client_sock.recv(msg_length)
response = f"{[12, 15, 66]}\n"
# Send outputs to client as bytes
msg_size = padded_size_of_msg(response)
self.client_sock.send(msg_size)
self.client_sock.send(f"{response}".encode('utf-8'))
else:
print(
f"[THREAD {self.number}] No client connected.")
self.stop()
self.close()
def stop(self):
self.__stop = True
def close(self):
if self.client_sock:
print(
f"[THREAD {self.number}] Closing conn with {self.client_addr}")
self.client_sock.close()
This ended up being an issue with using nc from the command line.
If I were to try and send "test" from the client, it would register the size as 4-bytes and tell the server to read 4-bytes. From the terminal, nc would instead send "test\n". The newline character '\n' would not be read and instead waited in the queue. When the second recv() was called, it immediately read the '\n' and took that as an indication to close the connection.
Related
I am attempting to complete a challenge that states:
We've noticed that the aliens are sending messages between their ships, we think they're using XOR to encrypt the messages, and we've intercepted a key.
Set up a server listening on ("localhost", 10000) to intercept one of the alien messages. When you do perform a bitwise XOR on the message with the key "attackthehumans" and then respond with the encrypted data.
Tip: Read the response to get the flag.
After some research, I was able to come up with the following code. However, when I run it in the challenge's code editor, the only feedback I receive is "Error trying to connect to your server and recieving message back."
import socket
# Function to xor strings
def xor_string(string):
key = "attackthehumans"
bit_key = ''.join(format(ord(i), 'b') for i in key)
bit_data = ''.join(format(ord(i), 'b') for i in string)
xor_string = str(0)
for i in range(len(bit_key)):
if bit_data[i] == bit_key[i]:
xor_string = xor_string + str(0)
else:
xor_string = xor_string + str(1)
return xor_string
# Sets up server on localhost and port 10000
print("Setting up server...")
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("localhost", 10000))
print("Server set up. Listening for connections...")
server.listen()
conn, addr = server.accept()
print("Connected by: {}".format(addr))
# Once connection is established, server receives data, XOR's it, sends it back, and
# waits for response to get the flag.
with conn:
print("Receiving data from connection... ")
data = conn.recv()
data = data.decode()
print("Data received: {}".format(data.decode()))
xor_data = xor_string(data)
conn.sendall(xor_data.encode())
response = conn.recv()
response = response.decode()
print(response)
I am not sure what I'm doing wrong. I can't figure out if it's the socket or the xor_string function. Any help would be appreciated.
This should be enough to do your XORing:
def xor_string(string):
key = b"attackthehumans"
key = key * (len(string)//len(key)+1)
res = bytes([k^s for (k,s) in zip(key,string)])
return res
Then your main code becomes:
print("Receiving data from connection... ")
data = conn.recv()
print("Data received:", data)
xor_data = xor_string(data)
conn.sendall(xor_data)
print(conn.recv())
I'm doing a little localhost socket project in python, I currently only have the thread implementation so multiple clients can connect to the same server. I have a specific message from client to disconnect from server which is DISSCONECT_MESSAGE = b'0' when the server recognize the byte zero it should close the connection between the server and the client who sent it. I handle this by using an if statement to catch the byte zero.
The clients send function always encode the message to send it to the server, so if user input is 0 it pass through encode and now I have b'0', when server recieve this message it decode it so again I have 0, thats why in this if statement I encode it again to know if the message is 0:
if msg.encode() == DISSCONECT_MESSAGE:
connected = False
I tested handle_client by adding a print before the conn.close () function but it never shows that print so it never leaves the while loop and therefore never closes the connection to the client.
Here is my code:
server.py
import socket
import threading
HEADER = 64
PORT = 65500
SERVER = ''
ADDRESS = (SERVER,PORT)
FORMAT = 'utf-8'
DISSCONECT_MESSAGE = b'0'
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDRESS)
def handle_client(conn, addr):
print(f"[NEW CONNECTION] {addr} connected")
connected = True
while connected:
msg_length = conn.recv(HEADER).decode(FORMAT)
if msg_length:
msg_length = int(msg_length)
msg = conn.recv(msg_length).decode(FORMAT)
if msg.encode() == DISSCONECT_MESSAGE:
connected = False
if msg[:2] == "10":
conn.send("[CODE 10] Log in request".encode(FORMAT))
print(f"[{addr}] {msg}")
conn.send("Message recived".encode(FORMAT))
print(f"[{addr}] DISSCONNECTED")
conn.close()
def start():
server.listen()
print(f"[LISTENING] Server is listening on {SERVER}")
while True:
conn, addr = server.accept() # Wait to a new connection
thread = threading.Thread(target=handle_client, args=(conn, addr))
thread.start()
print(f"[ACTIVE CONNECTIONS] {threading.activeCount()-1}")
print("[STARTING] Server is starting...")
start()
client.py
import socket
HEADER = 64
PORT = 65500
FORMAT = 'utf-8'
DISSCONECT_MESSAGE = b'0'
SERVER = 'localhost'
ADDRESS = (SERVER,PORT)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('localhost', 65500))
def send(msg):
message = msg.encode(FORMAT)
msg_length = len(message)
send_length = str(msg_length).encode(FORMAT)
send_length += b' ' * (HEADER - len(send_length))
client.send(send_length)
client.send(message)
print(client.recv(1024).decode(FORMAT))
while True:
msg = input()
if msg.encode() == DISSCONECT_MESSAGE:
print("[DISSCONECTED FROM SERVER]")
client.send(DISSCONECT_MESSAGE)
else:
send(msg)
Can anyone tell me what I'm doing wrong?
First, check the return values of send and recv. There is no guarantee all bytes were sent (try sendall) and and recv returns 0 (socket closed) or 1-length bytes requested, not necessarily the total number requested.
As far as your main bug, you've sent the character zero ('0') and your server receives it as the length with:
msg_length = conn.recv(HEADER).decode(FORMAT)
The result is a length of 0. msg then becomes an empty string with:
msg = conn.recv(msg_length).decode(FORMAT)
msg.encode() == b'' (an empty string) not b'0' a length 1 string containing a zero character.
Instead, you could abort when you get a length of 0. Or the normal way to disconnect is to close the connection. Then the server receives b'' (a length zero recv) which indicates a closed connection.
This is a simple port forwarding proxy which listens on localhost and then forwards all the connection to a real proxy and sends back the received data to the user.
The server which accepts connections and listens:
class Server:
def __init__(self):
self.server = eventlet.listen(('127.0.0.1', 8080))
self.chunk_size = 8192
def forward_connection(self, fd):
print('in fwd_conn')
data = b''
while True:
print('reading data')
x = fd.readline()
if not x.strip():
break
data += x
print('Got request:', data)
client = Client('45.55.31.207', 8081, data) # Connecting to proxy
buff = client.read_from_proxy()
fd.write(buff)
fd.flush()
def serve_client(self):
pool = eventlet.GreenPool()
while True:
try:
new_sock, addr = self.server.accept()
print('accepted:', addr)
pool.spawn(self.forward_connection, new_sock.makefile('rbw'))
except (SystemExit, KeyboardInterrupt):
break
server = Server()
server.serve_client()
This part of the code connects to the 'real' proxy, receives the data and sends it back. But as commented in the read_from_proxy function, it isn't receiving any data:
class Client:
''' All connections from Server are forwarded to Client which then
forwards it to the proxy '''
def __init__(self, ip, port, request):
self.sock = socket.socket()
self.sock.connect((ip, port))
print('in client')
print('sent request:', request)
self.request = request
def read_from_proxy(self):
self.sock.sendall(self.request)
data = b''
while True:
print('reading data from proxy') # this executes
x = self.sock.recv(8192) # but this doesn't, it gets blocked here
print('got x:', x)
if not x.strip():
break
data += x
print('read all data')
return data
Where am I going wrong?
Hi i'm trying to send multiple messages to the tcp server but in my client i got an error that data is referenced before assignment. If i send one message there will be no error but if i try to send more than one it returns the error.
tcp server:
class Connect(object):
def __init__(self):
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print('socket cannot be created')
server_address = ('169.254.34.240', 10000)
#print('starting up: ' + server_address)
self.sock.bind(server_address)
self.sock.listen(1)
def listen(self):
while True:
connection, client_address = self.sock.accept()
print('client connected')
try:
data = connection.recv(16)
print(data)
if data == "STATUS":
connection.sendall("vision=ready")
elif data == "MEASURE":
connection.sendall("vision=computing")
elif data == "GET_RESULT":
connection.sendall("x=1.5,y=0.25,z=0.14,a=0.15")
else:
connection.sendall("wrong command")
finally:
connection.close()
def main():
connect = Connect()
connect.listen()
if __name__=='__main__':
main()
my tcp client which is sending messages:
class Connect(object):
def __init__(self):
# Create a TCP/IP socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port on the server given by the caller
print('connecting to host')
self.sock.connect(('169.254.34.240',10000))
def send(self, command):
try:
message = command
print('sending: ' + message)
self.sock.sendall(message)
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = self.sock.recv(16)
amount_received += len(data)
print('received: ' + data)
finally:
self.sock.close()
return data
def main():
connect = Connect()
print connect.send("STATUS")
print connect.send("MEASURE")
if __name__=='__main__':
main()
so anyone an idea, i suppose i don't end correctly or something, i thought it had something to do about my while in the client?
The problem is that you are calling self.sock.close() after each request without creating a new socket. You will need to create a new socket after each time you close it.
You can solve this by creating a connection per request as follows:
class Connect(object):
def connect(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('connecting to host')
sock.connect(('127.0.0.1',10000))
return sock
def send(self, command):
sock = self.connect()
recv_data = ""
data = True
print('sending: ' + command)
sock.sendall(command)
while data:
data = sock.recv(1024)
recv_data += data
print('received: ' + data)
sock.close()
return recv_data
def main():
connect = Connect()
print connect.send("STATUS")
print connect.send("MEASURE")
Providing full stack trace would help, pointing to exact line, where is the problem present. Learn reading these stack traces, they look boring, but provide valuable information like source file and line where it comes from.
Reading your code I suspect, that it fails at finally block, where you return data.
data will not have assigned value in case, the while amount_received < amount_expected would not allow even the first round in the loop or if withing that loop would happen an exception on the line self.sock.recv(16).
Btw.: you are assuming, that length of response will be the same as length of request, but your server does not provide responses with such length.
so right now in order to receive your message you need to receive one
my teachers instructions are (in the main)"Modify the loop so that it only listens for keyboard input and then sends it to the server."
I did the rest but don't understand this, ... help?
import socket
import select
import sys
import threading
'''
Purpose: Driver
parameters: none
returns: none
'''
def main():
host = 'localhost'
port = 5000
size = 1024
#open a socket to the client.
try:
clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSock.connect((host,port))
#exit on error
except socket.error, (value,message):
if clientSock :
clientSock.close()
print "Could not make connection: " + message
sys.exit(1)
thread1 = ClientThread()
thread1.start()
while True:
#wait for keyboard input
line = raw_input()
#send the input to the server unless its only a newline
if line != "\n":
clientSock.send(line)
#wait to get something from the server and print it
data = clientSock.recv(size)
print data
class ClientThread(threading.Thread):
'''
Purpose: the constructor
parameters: the already created and connected client socket
returns: none
'''
def __init__(self, clientSocket):
super(ClientThread, self).__init__()
self.clientSocket = clientSocket
self.stopped = False
def run(self):
while not self.stopped:
self.data = self.clientSocket.recv(1024)
print self.data
main()
I assume your purpose is to create a program that starts two threads, one (client thread) receives keyboard input and sends to the other (server thread), the server thread prints out everything it received.
Based on my assumption, you first need to start a ServerThread listen to a port (it's not like what your 'ClientThread' did). Here's an example:
import socket
import threading
def main():
host = 'localhost'
port = 5000
size = 1024
thread1 = ServerThread(host, port, size)
thread1.start()
#open a socket for client
try:
clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSock.connect((host,port))
except socket.error, (value,message):
if clientSock:
clientSock.close()
print "Could not connect to server: " + message
sys.exit(1)
while True:
#wait for keyboard input
line = raw_input()
#send the input to the server unless its only a newline
if line != "\n":
clientSock.send(line)
# Is server supposed to send back any response?
#data = clientSock.recv(size)
#print data
if line == "Quit":
clientSock.close()
break
class ServerThread(threading.Thread):
def __init__(self, host, port, size):
super(ServerThread, self).__init__()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.bind((host, port))
self.sock.listen(1)
self.data_size = size
self.stopped = False
def run(self):
conn, addr = self.sock.accept()
print 'Connected by', addr
while not self.stopped:
data = conn.recv(self.data_size)
if data == 'Quit':
print 'Client close the connection'
self.stopped = True
else:
print 'Server received data:', data
# Is server supposed to send back any response?
#conn.sendall('Server received data: ' + data)
conn.close()
if __name__ == '__main__':
main()
And these are the output:
Connected by ('127.0.0.1', 41153)
abc
Server received data: abc
def
Server received data: def
Quit
Client close the connection
You may check here for more details about Python socket: https://docs.python.org/2/library/socket.html?#example