This is a console chat app on a TCP socket server. The client will send the request/message to the server and the server will distribute the message to the target user or provide requested information.I am currently running into a problem regarding the recv package on the server side. I received the package and was able to print it out. However the system still give me a syntax error for some reason.
Thanks.
This is my client:
import socket
import select
import errno
import sys, struct
import pickle
HEADER_LENGTH = 1024
IP = "127.0.0.1"
PORT = 9669
def send_login_request(username):
package = [1]
length = len(username)
if length > 1019:
print ("Error: Username too long")
sys.exit()
package += struct.pack("I", length)
package += username
return package
def send_message(recv_id, message):
package = [2]
length = len(message)
if length > 1015:
print('message too long')
sys.exit()
package += recv_id
package += struct.pack('I', length)
package += message
return package
def send_con_request(conv_id):
package = [3]
length = len(id)
if length > 1015:
print('id too long')
sys.exit()
package += struct.pack("I", length)
package += conv_id
return package
# Create a socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to a given ip and port
client_socket.connect((IP, PORT))
client_socket.setblocking(False)
my_username = input("Username: ")
request = send_login_request(my_username)
user_request = str(request)
client_socket.send(user_request.encode())
username_conf = client_socket.recv(HEADER_LENGTH).decode()
if username_conf == "Welcome to the server":
con_id = input("Please enter conversation's id, if don't have one, please enter no ")
if con_id == 'no':
con_request = send_con_request(con_id)
con_request = str(con_request)
client_socket.send(con_request.encode())
else:
con_request = send_con_request(con_id)
con_request = str(con_request)
client_socket.send(con_request.encode())
conversation = client_socket.recv(HEADER_LENGTH).decode()
recv_id = input("Please enter receiver's id")
while True:
# Wait for user to input a message
message = input(f'{my_username} > ').encode()
# If message is not empty - send it
if message:
send_message = send_message(recv_id,message)
client_socket.send(bytes(send_message))
try:
while True:
message_receiver = client_socket.recv(HEADER_LENGTH).decode()
x = message_receiver.split('|')
print(x)
username = x[0]
message = x[1]
# Print message
print(f'{username} > {message}')
except IOError as e:
if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
print('Reading error: {}'.format(str(e)))
sys.exit()
# We just did not receive anything
continue
except Exception as e:
# Any other exception - something happened, exit
print('Reading error: {}'.format(str(e)))
sys.exit()
This is my server:
import socket
import select
import struct
import sys
import pickle
HEADER_LENGTH = 1024
conversation ={}
users = [
{
'username': 'user1',
'user_id': 1
},
{
'username': 'user2',
'user_id': 2
},
{
'username': 'user3',
'user_id': 3
},
{
'username': 'user4',
'user_id': 4
},
{
'username': 'user5',
'user_id': 5
}
]
def login(username):
for user in users:
if user['username'] == username:
return user
else:
return False
IP = "127.0.0.1"
PORT = 9669
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((IP, PORT))
server_socket.listen()
# List of sockets for select.select()
sockets_list = [server_socket]
# List of connected clients - socket as a key, user header and name as data
clients_socket = {}
sessions = {
(1,2) : '1.txt',
(3,4) : '2.txt'
}
def getRecvSocket(user_id):
try:
return sessions[user_id]
except:
return None
def sendErrorMes(socketid, mes):
package = [9]
length = len(mes)
if length > 1019:
length = 1019
package += struct.pack("I", length)
package += mes
print(f'Listening for connections on {IP}:{PORT}...')
# Handles message receiving
def receive_message(client_socket):
try:
receive_message = client_socket.recv(HEADER_LENGTH)
return receive_message
except:
return False
while True:
read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
# Iterate over notified sockets
for notified_socket in read_sockets:
# If notified socket is a server socket - new connection, accept it
if notified_socket == server_socket:
client_socket, client_address = server_socket.accept()
sockets_list.append(client_socket)
else:
# Receive message
package = receive_message(notified_socket)
print(package)
package_recv = eval(package.decode())
print(package_recv)
print(type(package_recv))
package_type = package_recv[0]
if package_type == 1:
size = struct.unpack("I", package[1:5])
if size[0] > 1019:
continue
username = package[5:5+size[0]]
username = username.decode()
# username = package_recv[1]
user = login(username)
if user == False:
notified_socket.send("no user found".encode())
else:
sessions[user["user_id"]] = notified_socket
notified_socket.send(("Welcome to the server").encode())
elif package_type == 2:
recv_id = struct.unpack("I", package[1:5])
size = struct.unpack("I", package[5:9])
if size[0] > 1015:
continue
# recv_id = package_recv[1]
if getRecvSocket(recv_id) == None:
sendErrorMes(notified_socket, "User is offline")
else:
message = package[9:9+size[0]]
# message = package_recv[2]
for socket in sessions.values():
if socket == notified_socket:
user = sessions[notified_socket]
# print(f'Received message from {user}, {message}')
# fIterate over connected clients and broadcast message
for client_socket in clients_socket:
# if clients[client_socket] == receive_user and client_socket != notified_socket:
# But don't sent it to sender
if client_socket != notified_socket and clients_socket[client_socket] == recv_id:
# Send user and message (both with their headers)
# We are reusing here message header sent by sender, and saved username header send by user when he connected
a = sessions[notified_socket]
b = recv_id
with open(f"{conversation[a,b]}.txt", "w"):
f.write(user + message)
client_socket.send((user + "|" + message).encode())
if message is False:
# print('Closed connection from: {}'.format(user))
# Remove from list for socket.socket()
sockets_list.remove(notified_socket)
# Remove from our list of users
del clients_socket[notified_socket]
continue
elif package_type == 3:
size = struct.unpack("I", package[1:5])
if size[0] > 1019:
continue
convo_id = package[5:5+size[0]]
convo_id = convo_id.decode()
# convo_id = package_recv[2]
if convo_id in conversation:
with open(conversation[convo_id], 'rb') as file_to_send:
for data in file_to_send:
notified_socket.sendall(data)
print('send successful')
else:
f = open(f"{len(conversation)+1}.txt", "w+")
This is the error in the server side which I am having a problem to locate and solve:
Listening for connections on 127.0.0.1:9669...
b"[1, 5, 0, 0, 0, 'u', 's', 'e', 'r', '1']"
[1, 5, 0, 0, 0, 'u', 's', 'e', 'r', '1']
<class 'list'>
b''
Traceback (most recent call last):
File "c:/Users/Duong Dang/Desktop/bai 2.3/server.py", line 134, in <module>
package_recv = eval(package.decode())
File "<string>", line 0
^
SyntaxError: unexpected EOF while parsing
The sending code doesn't make a lot of sense. You're creating a python list which is a most strange way to implement a protocol. You're then taking python's string representation of that list and sending it to the server. You're not doing anything on the server side to ensure that you got the entire message. Then you're using eval to interpret the string you created on the client. That is a very dangerous practice, as your peer can essentially instruct your python interpreter to do literally anything.
Also, your send_con_request is calling len(id) which won't work at all because id is a python built-in that doesn't supply a __len__ method. I assume that was supposed to be len(conv_id)?
Anyway, you should rework your protocol. Use the struct tools to create the correct binary string you want. There are tons of possible ways to structure this but here's one. On the client side, create a fixed-length header that identifies which request type you're sending and the length of the remaining "payload" bytes. You'll convert your string (username or whatever) into bytes first with str.encode.
import struct
# ProtoHeader encodes a 16 bit request identifer, plus a 32 bit payload
# length. A protocol data unit consists of this 6-byte header followed by
# payload bytes (which will vary according to the request)
ProtoHeader = struct.Struct("!HI")
LoginRequest = 1
SomeOtherRequest = 2
...
def format_login_request(username):
""" Create a protocol block containing a user login request.
Return the byte string containing the encoded request """
username_bytes = username.encode()
proto_block = ProtoHeader.pack(LoginRequest, len(username_bytes)) + username_bytes
return proto_block
...
conn.sendall(format_login_request(username))
On the server side, you will first receive the fixed-length header (which tells you what the request type was and how many other payload bytes are present). Then receive those remaining bytes ensuring that you get exactly that many. socket.recv does not guarantee that you will receive exactly the number of bytes sent in any particular send from the peer. It does guarantee that you will get them in the right order so you must keep receiving until you got exactly the number you expected. That's why it's important to have fixed length byte strings as a header and to encode the number of bytes expected in variable length payloads.
The server would look something like this:
import struct
ProtoHeader = struct.Struct("!HI")
LoginRequest = 1
def receive_bytes(conn, count):
""" General purpose receiver:
Receive exactly #count bytes from #conn """
buf = b''
remaining = count
while remaining > 0:
# Receive part or all of data
tbuf = conn.recv(remaining)
tbuf_len = len(tbuf)
if tbuf_len == 0:
# Really you probably want to return 0 here if buf is empty and
# allow the higher-level routine to determine if the EOF is at
# a proper message boundary in which case, you silently close the
# connection. You would normally only raise an exception if you
# EOF in the *middle* of a message.
raise RuntimeError("end of file")
buf += tbuf
remaining -= tbuf_len
return buf
def receive_proto_block(conn):
""" Receive the next protocol block from #conn. Return a tuple of
request_type (integer) and payload (byte string) """
proto_header = receive_bytes(conn, ProtoHeader.size)
request_type, payload_length = ProtoHeader.unpack(proto_header)
payload = receive_bytes(conn, payload_length)
return request_type, payload
...
request_type, payload = receive_proto_block(conn)
if request_type == LoginRequest:
username = payload.decode()
Related
So my project is that I need to send a jpg image from one computer to another computer in the same network. To send the data I split the data into chunks of at least 9999 bytes and then I create a length header that tells the length of the data and I attach it to the start of the massage. here is the code:
the protocol:
import os.path
LENGTH_FIELD_SIZE = 4
PORT = 8820
COMANDS_LIST = "TAKE_SCREENSHOT\nSEND_PHOTO\nDIR\nDELETE\nCOPY\nEXECUTE\nEXIT".split("\n")
def check_cmd(data):
"""
Check if the command is defined in the protocol, including all parameters
For example, DELETE c:\work\file.txt is good, but DELETE alone is not
"""
command = ""
file_location =""
splited_data = data.split(maxsplit=1)
if len(splited_data) == 2:
command, file_location = splited_data
return (command in COMANDS_LIST) and (file_location is not None)
elif len(splited_data) == 1:
command = splited_data[0]
return command in ["TAKE_SCREENSHOT","EXIT","SEND_PHOTO"]
return False
# (3)
def create_msg(data):
"""
Create a valid protocol message, with length field
"""
data_len = len(str(data))
if data_len > 9999 or data_len == 0:
print(f"data len is bigger then 9999 or is 0, data len = {data_len} ")
return False
len_field = str(data_len).zfill(4)
# (4)
print(len_field)
return True ,f"{len_field}{data}"
def get_msg(my_socket):
"""
Extract message from protocol, without the length field
If length field does not include a number, returns False, "Error"
"""
lenght_field = ""
data = ""
try:
while len(lenght_field) < 4:
lenght_field += my_socket.recv(4).decode()
except RuntimeError as exc_run:
return False, "header wasnt sent properly"
if not lenght_field.isdigit():
return False, "error, length header is not valid"
lenght_field = lenght_field.lstrip("0")
while len(data) < int(lenght_field):
data += my_socket.recv(int(lenght_field)).decode()
return True, data
now the protocol works fine when I use the same computer for both server and client and when I debug get_msg on the other computer. when I'm not, it seems that the problem is that the part that recv the header will recv something else after a few successful recv and return an error message.
here are the server parts:
import socket
import pyautogui as pyautogui
import protocol
import glob
import os.path
import shutil
import subprocess
import base64
IP = "0.0.0.0"
PORT = 8820
PHOTO_PATH = r"C:\Users\Innon\Pictures\Screenshots\screenShot.jpg"# The path + filename where the screenshot at the server should be saved
def check_client_request(cmd):
"""
Break cmd to command and parameters
Check if the command and params are good.
For example, the filename to be copied actually exists
Returns:
valid: True/False
command: The requested cmd (ex. "DIR")
params: List of the cmd params (ex. ["c:\\cyber"])
"""
# Use protocol.check_cmd first
cmd_arr = cmd.split(maxsplit=1)
command = cmd_arr[0]
file_location = None
if len(cmd_arr) == 2:
file_location = cmd_arr[1]
if file_location == None:
return protocol.check_cmd(cmd) ,command, file_location
else:
file_location = tuple(str(file_location).split())
if (os.path.exists(file_location[0])):
return protocol.check_cmd(cmd) , command , file_location
return False , command , file_location
# Then make sure the params are valid
# (6)
def handle_client_request(command,params):
"""Create the response to the client, given the command is legal and params are OK
For example, return the list of filenames in a directory
Note: in case of SEND_PHOTO, only the length of the file will be sent
Returns:
response: the requested data
"""
# (7)
response = "no server response"
if command == "DIR":
response = glob.glob(f"{params[0]}\\*.*" )
if command == "DELETE":
os.remove(params[0])
response = f"{params[0]} was deleted"
if command == "COPY":
try:
shutil.copy(params[0],params[1])
response = f"{params[0]} was copyed to {params[1]}"
except FileNotFoundError as ex1:
response = ex1
except IndexError as ex2:
response = ex2
if command == "EXECUTE":
subprocess.call(params[0])
response = f"{params[0]} was executed"
if command == "TAKE_SCREENSHOT":
#todo find a way to know and create the locatipn of screen shot to be saved
myScreenshot = pyautogui.screenshot()
myScreenshot.save(PHOTO_PATH)
response = f"screen shot have been taken and been saved at {PHOTO_PATH}"
if command == "SEND_PHOTO":
with open(PHOTO_PATH, "rb") as file:
file_data = base64.b64encode(file.read()).decode()
print(file_data)
is_vaild_response, img_length = protocol.create_msg(len(file_data))
print(img_length)
img_data = ""
if not is_vaild_response:
response = "img length data isnt valid"
return response
while len(file_data) > 0:
chunk_data = file_data[:9999]
is_vaild_response, data = protocol.create_msg(chunk_data)
if not is_vaild_response:
response = "img data isnt valid"
return response
img_data += data
file_data = file_data[9999:]
response = f"{img_length}{img_data}"
return response
def main():
# open socket with client
server_socket = socket.socket()
server_socket.bind((IP,PORT))
server_socket.listen(1)
# (1)
client_socket, addr = server_socket.accept()
# handle requests until user asks to exit
while True:
# Check if protocol is OK, e.g. length field OK
valid_protocol, cmd = protocol.get_msg(client_socket)
print(f"got message {valid_protocol}")
if valid_protocol:
# Check if params are good, e.g. correct number of params, file name exists
valid_cmd, command, params = check_client_request(cmd)
print(f"check_client_request {valid_cmd}")
if valid_cmd:
# (6)
if command == 'EXIT':
break
if command == 'SEND_PHOTO':
data = handle_client_request(command, params)
client_socket.sendall(data.encode())
continue
# prepare a response using "handle_client_request"
data = handle_client_request(command,params)
# add length field using "create_msg"
is_vaild_response , response = protocol.create_msg(data)
print(f"creat_msg {is_vaild_response}")
# send to client
if is_vaild_response:
client_socket.sendall(response.encode())
else:
# prepare proper error to client
resp = 'Bad command or parameters'
is_vaild_response , response = protocol.create_msg(resp)
# send to client
client_socket.sendall(response.encode())
else:
# prepare proper error to client
resp = 'Packet not according to protocol'
is_vaild_response, response = protocol.create_msg(resp)
#send to client
client_socket.sendall(response.encode())
# Attempt to clean garbage from socket
client_socket.recv(1024)
# close sockets
resp = "Closing connection"
print(resp)
is_vaild_response, response = protocol.create_msg(resp)
client_socket.sendall(response.encode())
client_socket.close()
server_socket.close()
if __name__ == '__main__':
main()
and the client:
import socket
import base64
import protocol
IP = "127.0.0.1"
SAVED_PHOTO_LOCATION = r'C:\Users\Innon\Pictures\Saved Pictures\screenShot.jpg' # The path + filename where the copy of the screenshot at the client should be saved
def handle_server_response(my_socket, cmd):
"""
Receive the response from the server and handle it, according to the request
For example, DIR should result in printing the contents to the screen,
Note- special attention should be given to SEND_PHOTO as it requires and extra receive
"""
# (8) treat all responses except SEND_PHOTO
if "SEND_PHOTO" not in cmd:
vaild_data, data = protocol.get_msg(my_socket)
if vaild_data:
return data
# (10) treat SEND_PHOTO
else:
pic_data = ""
vaild_pick_len, pic_len = protocol.get_msg(my_socket)
if pic_len.isdigit() == False:
print(f"picture length is not valid. got massage: {pic_len}")
return
with open(SAVED_PHOTO_LOCATION, "wb") as file:
while len(pic_data) < int(pic_len):
vaild_data, data = protocol.get_msg(my_socket)
if not vaild_data:
return f"img data isnt valid. {data}"
pic_data += data
print(pic_data)
file.write(base64.b64decode(pic_data.encode()))
return "img was recived succesfully "
def main():
# open socket with the server
my_socket = socket.socket()
my_socket.connect((IP,8820))
# (2)
# print instructions
print('Welcome to remote computer application. Available commands are:\n')
print('TAKE_SCREENSHOT\nSEND_PHOTO\nDIR\nDELETE\nCOPY\nEXECUTE\nEXIT')
# loop until user requested to exit
while True:
cmd = input("Please enter command:\n")
if protocol.check_cmd(cmd):
valid_pack , packet = protocol.create_msg(cmd)
if valid_pack:
my_socket.sendall(packet.encode())
print(handle_server_response(my_socket, cmd))
if cmd == 'EXIT':
break
else:
print("Not a valid command, or missing parameters\n")
my_socket.close()
if __name__ == '__main__':
main()
here is how the problem looks like:thi is how it looks
here is how to needs look like:
the right way
thank you.
the solution was to change get_msg function in the protocol:
while len(data) < int(lenght_field):
data += my_socket.recv(int(lenght_field) - len(data)).decode()
instead of:
while len(data) < int(lenght_field):
data += my_socket.recv(int(lenght_field)).decode()
I am trying to build a console chat app on Python socket. I currently running into some issues regarding the server sending message to the client. I managed to successfully send the request from the client to the server and printed it out. However, when I try to sent the confirmation message back to the client, there were always problems that I couldn't quite understand.
Here is my client side:
import socket
import select
import errno
import sys, struct
HEADER_LENGTH = 1024
IP = "127.0.0.1"
PORT = 9669
ProtoHeader = struct.Struct("!HI")
LoginRequest = 1
MessageRequest = 2
ConversationRequest = 3
def format_login_request(username):
username_bytes = username.encode()
proto_block = ProtoHeader.pack(LoginRequest, len(username_bytes)) + username_bytes
return proto_block
def format_send_message(recv_id, message):
message_bytes = message.encode()
recv_id = recv_id.encode()
proto_block = ProtoHeader.pack(MessageRequest, len(message_bytes)+len(recv_id)) + recv_id+message_bytes
return proto_block
def format_con_request(conv_id):
recv_id_bytes = recv_id.encode()
proto_block = ProtoHeader.pack(ConversationRequest, len(recv_id_bytes)) + recv_id_bytes
return proto_block
# Create a socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to a given ip and port
client_socket.connect((IP, PORT))
client_socket.setblocking(False)
my_username = input("Username: ")
print(format_login_request(my_username))
client_socket.sendall(format_login_request(my_username))
username_conf = client_socket.recv(HEADER_LENGTH).decode()
print(username_conf)
if username_conf == "Welcome to the server":
con_id = input("Please enter conversation's id, if don't have one, please enter no ")
if con_id == 'no':
client_socket.send(format_con_request(con_id))
else:
client_socket.send(format_con_request(con_id))
conversation = client_socket.recv(HEADER_LENGTH).decode()
recv_id = input("Please enter receiver's id")
while True:
# Wait for user to input a message
message = input(f'{my_username} > ')
# If message is not empty - send it
if message:
# send_message = send_message(recv_id,message)
client_socket.sendall(format_send_message(recv_id,message))
try:
while True:
message_receiver = client_socket.recv(HEADER_LENGTH).decode()
x = message_receiver.split('|')
print(x)
username = x[0]
message = x[1]
# Print message
print(f'{username} > {message}')
except IOError as e:
if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
print('Reading error: {}'.format(str(e)))
sys.exit()
# We just did not receive anything
continue
except Exception as e:
# Any other exception - something happened, exit
print('Reading error: {}'.format(str(e)))
sys.exit()
Here is the console terminal for client:
Username: user1
b'\x00\x01\x00\x00\x00\x05user1'
Traceback (most recent call last):
File "C:\Users\Duong Dang\Desktop\bai 2.3\client.py", line 57, in <module>
username_conf = client_socket.recv(HEADER_LENGTH).decode()
BlockingIOError: [WinError 10035] A non-blocking socket operation could not be completed immediately
Here is my server side:
import socket
import select
import struct
import sys
import pickle
ProtoHeader = struct.Struct("!HI")
LoginRequest = 1
MessageRequest = 2
ConversationRequest = 3
HEADER_LENGTH = 1024
conversation ={}
users = [
{
'username': 'user1',
'user_id': 1
},
{
'username': 'user2',
'user_id': 2
},
{
'username': 'user3',
'user_id': 3
},
{
'username': 'user4',
'user_id': 4
},
{
'username': 'user5',
'user_id': 5
}
]
def login(username):
for user in users:
if user['username'] == username:
return user
else:
return False
IP = "127.0.0.1"
PORT = 9669
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((IP, PORT))
server_socket.listen()
# List of sockets for select.select()
sockets_list = [server_socket]
# List of connected clients - socket as a key, user header and name as data
clients_socket = {}
sessions = {}
conversation = {
(1,2) : '1.txt',
(3,4) : '2.txt'
}
def getRecvSocket(user_id):
try:
return sessions[user_id]
except:
return None
# def sendErrorMes(socketid, mes):
# package = [9]
# length = len(mes)
# if length > 1019:
# length = 1019
# package += struct.pack("I", length)
# package += mes
# package = pad(package)
print(f'Listening for connections on {IP}:{PORT}...')
def receive_bytes(conn, count):
""" General purpose receiveer:
Receive exactly #count bytes from #conn"""
buf = b''
remaining = count
while remaining > 0:
#Receive part of all of data
tbuf = conn.recv(remaining)
tbuf_len = len(tbuf)
if tbuf_len == 0:
#return 0 if buf is empty and allow the higher-level routine to determine
#if the EOF is at a proper message boundary in which case, you silently close
#the connection. You would normally only raise an exception if you EOF in the
#middle of the message.
raise RuntimeError("end of file")
buf += tbuf
remaining -= tbuf_len
return buf
def receive_proto_block(conn):
"""Receive the next protocol block from #conn. Return a tuple of request_type(interger)
and payload (byte string) """
proto_header = receive_bytes(conn, ProtoHeader.size)
request_type, payload_length = ProtoHeader.unpack(proto_header)
payload = receive_bytes(conn, payload_length)
return request_type, payload
while True:
read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
# Iterate over notified sockets
for notified_socket in read_sockets:
# If notified socket is a server socket - new connection, accept it
if notified_socket == server_socket:
client_socket, client_address = server_socket.accept()
sockets_list.append(client_socket)
else:
# Receive message
request_type, payload = receive_proto_block(notified_socket)
print(request_type)
print(payload.decode())
if request_type == LoginRequest:
username = payload.decode()
print(username)
user = login(username)
if user == False:
notified_socket.send("no user found".encode())
else:
sessions[user["user_id"]] = notified_socket
print(sessions)
notified_socket.send(("Welcome to the server").encode())
elif request_type == 2:
recv_package = payload.decode()
recv_id = recv_package[0]
print(message)
# if getRecvSocket(recv_id) == None:
# sendErrorMes(notified_socket, "User is offline")
message = recv_package[1]
for socket in sessions.values():
if socket == notified_socket:
user = sessions[notified_socket]
# fIterate over connected clients and broadcast message
for client_socket in clients_socket:
# if clients[client_socket] == receive_user and client_socket != notified_socket:
# But don't sent it to sender
if client_socket != notified_socket and clients_socket[client_socket] == recv_id:
# Send user and message (both with their headers)
# We are reusing here message header sent by sender, and saved username header send by user when he connected
a = sessions[notified_socket]
b = recv_id
with open(f"{conversation[a,b]}.txt", "w"):
f.write(user + message)
client_socket.send((user + "|" + message).encode())
if message is False:
# print('Closed connection from: {}'.format(user))
# Remove from list for socket.socket()
sockets_list.remove(notified_socket)
# Remove from our list of users
del clients_socket[notified_socket]
continue
elif request_type == 3:
convo_id = payload.decode()
if convo_id in conversation:
with open(conversation[convo_id], 'rb') as file_to_send:
for data in file_to_send:
notified_socket.sendall(data)
print('send successful')
else:
f = open(f"{len(conversation)+1}.txt", "w+")
and here is the console terminal for the server:
Listening for connections on 127.0.0.1:9669...
1
user1
user1
{1: <socket.socket fd=432, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9669), raddr=('127.0.0.1', 52919)>}
Traceback (most recent call last):
File "c:/Users/Duong Dang/Desktop/bai 2.3/server.py", line 137, in <module>
request_type, payload = receive_proto_block(notified_socket)
File "c:/Users/Duong Dang/Desktop/bai 2.3/server.py", line 115, in receive_proto_block
proto_header = receive_bytes(conn, ProtoHeader.size)
File "c:/Users/Duong Dang/Desktop/bai 2.3/server.py", line 97, in receive_bytes
tbuf = conn.recv(remaining)
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
Thanks for the help.
I'm trying to make a server-client program, where server will listen to client's messages and depends on the message, will response. I send a message from client with username and content, server accept it and print a message to sending to client Till here is everything fine. But when it comes to sending a message server will throw and error:
`TypeError: byte indices must be integers or slices, not str`
It looks like this line is the problem, but I'm not sure....
`clientsocket.send(msg['header'] + msg['data'])`
here is a whole server code. Please let me know, if client code is necessary too please.
import socket
import time
import pickle
import select
HEADERSIZE = 10
IP = "127.0.0.1"
PORT = 1234
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((IP, PORT))
s.listen()
sockets_list = [s]
clients = {}
# Handles message receiving
def receive_message(clientsocket):
try:
message_header = clientsocket.recv(HEADERSIZE)
if not len(message_header):
return False
message_length = int(message_header.decode('utf-8').strip())
return {'header': message_header, 'data': clientsocket.recv(message_length)}
except:
return False
while True:
read_sockets, _, exception_socket = select.select(sockets_list, [], sockets_list)
for notified_socket in read_sockets:
if notified_socket == s:
clientsocket, address = s.accept()
user = receive_message(clientsocket)
if user is False:
continue
sockets_list.append(clientsocket)
clients[clientsocket] = user
print(f"Connection from {address[0]}:{address[1]} has been estabilished! User:{user['data'].decode('utf-8')}")
else:
message = receive_message(notified_socket)
if message is False:
print(f"Close connection from {clients[notified_socket]['data'].decode('utf-8')}")
sockets_list.remove(notified_socket)
del clients[notified_socket]
continue
user = clients[notified_socket]
#message_decoded = message['data'].decode('utf-8')
print(f'Received message from {user["data"].decode("utf-8")}: {message["data"].decode("utf-8")}')
for clientsocket in clients:
if clientsocket == notified_socket:
if message["data"].decode("utf-8") == "y":
#d = {1: "Hey", 2: "there"}
msg = pickle.dumps("th.jpeg")
print(msg)
msg = bytes(f'{len(msg):<{HEADERSIZE}}', "utf-8") + msg
clientsocket.send(msg['header'] + msg['data'])
else:
d = {1: "Hey", 2: "there"}
msg = pickle.dumps(d)
print(msg)
# msg = bytes(f'{len(msg):<{HEADERSIZE}}', "utf-8") + msg
clientsocket.send(msg['header'] + msg['data'])
for notified_socket in exception_socket:
sockets_list.remove(notified_socket)
del clients[notified_socket]
HERE is a whole error code:
Connection from 127.0.0.1:48480 has been estabilished! User:j
Received message from j: y
b'\x80\x03X\x07\x00\x00\x00th.jpegq\x00.'
Traceback (most recent call last):
File "server.py", line 69, in <module>
clientsocket.send(msg['header'] + msg['data'])
TypeError: byte indices must be integers or slices, not str
As You can see, it works till sending the message line
msg = pickle.dumps("th.jpeg") will encode the string "th.jpeg" as a bytes-object.
msg = bytes(f'{len(msg):<{HEADERSIZE}}', "utf-8") + msg just adds that bytes object to another bytes-object.
So msg is a simple bytes-object, not any kind of server packet or similar. Therefor it is not possible to subscribe msg with msg['header'] or any other string.
Your code seems a little weird but maybe just try this line:
clientsocket.send(msg)
Since you are already converting msg to a bytes-object, it can be sent to the client directly. You just have to decode it properly in the client.
I'm implementing a circular distributed hash table, each peer knows its immediate successor and set up TCP connection with its successor, like, 1->3->4->5->8->1.
User will input a 4-digit number, and we proceed it into a certain value using a hash function written by us. For example, user inputs 3456, corresponding hash value is 128. Peer 3 get the input from user, and pass the hash value to its successor(4) asking if he is greater than hash value. If not, the successor will pass the hash to its successor(5). Repeat this until it find the right peer. (Here, since 8 < 128, we say peer 1 is the one we want)
Now, we know peer 1 is the peer we want. Then we let peer 1 make a TCP connection with the requesting peer 3, and send 3 "FIND1,3456,3", when peer 3 get this message, it should print out "peer 1 has the value".
The problem I met is, after I find peer 1 is the one I want, my peer 1 client sets up TCP connection with peer 3 server (peer 1 client said the connection is set up), but peer 3 doesn't get any message from peer 1, what's wrong with it?
How should I fix it?
Thanks for your patience to read these, feel free to ask if there is anything ambiguous :)
#!/usr/bin/python2.7
import sys
import socket
import time
import threading
import re
from collections import defaultdict
successor = defaultdict(dict)
peer = int(sys.argv[1])
successor[1] = int(sys.argv[2])
successor[2] = int(sys.argv[3])
serverName = 'localhost'
peerPort = 50000 + int(peer)
address = (serverName,peerPort)
#-------------proceed input string---------------------------
def getFileNum(name):
fileValid = re.match('^request ([0-9]{4})$',name)
if fileValid is None:
print 'invalid file!'
return
else:
hashName = fileValid.group(1)
return hashName
#----------------get request input--------------------------------
def getRequestInput(clientSocketTCP):
while flag == 0:
fileName = raw_input()
hashname = getFileNum(fileName)
if hashname is not None:
hashname = re.sub('^(0)*','',hashname)
hashnum = int(hashname) % 256
info = 'FILE_REQUEST'+str(hashname) + ','+ str(hashnum) + ','+ str(peer) + ',1'
clientSocketTCP.send(info)
print 'File request message for '+ str(hashname) + ' has been sent to my successor.'
clientSocketTCP.close()
#-------------------send file to successor---------------------------
def sendRequestToS(clientSocketTCP):
global important
while flag == 0:
if important:
an = re.match('^FILE_REQUEST([0-9]{4}),',important)
if an:
hashname = an.group(1)
clientSocketTCP.send(important)
print 'File request message for '+ str(hashname) + ' has been sent to my successor.'
important = ''
clientSocketTCP.close()
#-----------------------find file-------------------------------------
def findF():
global flag
global important
while flag == 0:
if re.match('^FIND',important):
obj = re.match('^FIND[0-9]{1,3},([0-9]{4}),([0-9]{1,3})',important)
n = int(obj.group(2))
info = important
ff = threading.Thread(target=clientTCPTemp,args=(n,info))
ff.start()
ff.join()
important = ''
#--------------------set up client temporary---------------------------
def clientTCPTemp(n,info):
global flag
clientConn = False
clientSocketTCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverPortTCP = 50000 + n
print serverPortTCP
while not clientConn:
try:
clientSocketTCP.connect((serverName,serverPortTCP))
clientConn = True
print "Now client connection works!!!!!"
except:
print "fail"
clientSocketTCP.send(info)
print info
print 'A response message, destined for peer '+ str(n) +', has been sent.'
clientSocketTCP.close()
#--------------------TCP server---------------------------------------
def serverTCP():
global flag
global serverSetUp
global important
serverSocketTCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverConn = False
while not serverConn:
try:
serverSocketTCP.bind((serverName,peerPort))
serverConn = True
serverSocketTCP.listen(2)
serverSetUp = 0
print 'The server is ready to receive'
except:
pass
while flag == 0:
connectionSocket, addr = serverSocketTCP.accept()
print 'connect by'+ str(addr)
threeinfo = connectionSocket.recv(1024)
print threeinfo
if re.match('^FILE_REQUEST',threeinfo):
obj = re.match('^FILE_REQUEST([0-9]{4}),([0-9]{1,3}),([0-9]{1,3}),([01])$',threeinfo)
if obj is not None:
filename = obj.group(1)
hashn = int(obj.group(2))
peerID = int(obj.group(3))
endCircle = int(obj.group(4))
if peer < hashn and endCircle:
print 'File ' +filename +' is not stored here. '
important = threeinfo
if peer > successor[1]:
important = re.sub('1$','0',threeinfo)
else:
print 'File '+ filename+' is here.'
important = 'FIND'+str(peer)+','+ filename +','+ str(peerID)
elif re.match('^FIND',threeinfo):
dest = re.match('^FIND([0-9]{1,3}),([0-9]{4})','',threeinfo)
fromP = dest.group(1)
fileP = dest.group(2)
print 'Received a response message from peer '+fromP+', which has the file '+fileP
connectionSocket.send('i receive from you------------------------')
print sen
connectionSocket.send('can you hear me?')
connectionSocket.close()
#--------------------TCP client----------------------------------------
def clientTCP(n):
global flag
global serverSetUp
global important
clientConn = False
# while serverSetUp == 1:
# pass
clientSocketTCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverPortTCP = 50000 + n
while not clientConn:
try:
clientSocketTCP.connect((serverName,serverPortTCP))
clientConn = True
print "Now client connection works!!!!!"
except:
pass
try:
rt = threading.Thread(target=getRequestInput,args=(clientSocketTCP,))
sr = threading.Thread(target=sendRequestToS,args=(clientSocketTCP,))
ff = threading.Thread(target=findF,args=())
rt.start()
sr.start()
ff.start()
except:
print 'thread failed'
sen = raw_input()
clientSocketTCP.send(sen)
m = clientSocketTCP.recv(1024)
print m
clientSocketTCP.close()
#----------------start thread---------------------------------
#------adapt from https://www.tutorialspoint.com/python/python_multithreading.html --------
flag = 0
serverSetUp = 1
important = ''
findFile = False
try:
serTCP = threading.Thread(target=serverTCP,args=())
cliTCP = threading.Thread(target=clientTCP,args=(successor[1],))
serTCP.start()
cliTCP.start()
except:
print "thread can not be set up"
while flag == 0:
try:
pass
except KeyboardInterrupt:
flag = 1
This question already has answers here:
Importing installed package from script with the same name raises "AttributeError: module has no attribute" or an ImportError or NameError
(2 answers)
Closed 7 months ago.
I am trying to run this simple Python WebSocket, with a couple very minor changes. I am running Python 2.4.3 because I cannot use an newer version, but I'm not sure how much that matters.
Here is the error I'm getting:
Traceback (most recent call last):
File "socket.py", line 258, in ?
server = WebSocketServer("localhost", 8000, WebSocket)
File "socket.py", line 205, in __init__
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
AttributeError: 'module' object has no attribute 'AF_INET'
And here is my code:
import time
import struct
import socket
import base64
import sys
from select import select
import re
import logging
from threading import Thread
import signal
# Simple WebSocket server implementation. Handshakes with the client then echos back everything
# that is received. Has no dependencies (doesn't require Twisted etc) and works with the RFC6455
# version of WebSockets. Tested with FireFox 16, though should work with the latest versions of
# IE, Chrome etc.
#
# rich20b#gmail.com
# Adapted from https://gist.github.com/512987 with various functions stolen from other sites, see
# below for full details.
# Constants
MAGICGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
TEXT = 0x01
BINARY = 0x02
# WebSocket implementation
class WebSocket(object):
handshake = (
"HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
"Upgrade: WebSocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: %(acceptstring)s\r\n"
"Server: TestTest\r\n"
"Access-Control-Allow-Origin: http://localhost\r\n"
"Access-Control-Allow-Credentials: true\r\n"
"\r\n"
)
# Constructor
def __init__(self, client, server):
self.client = client
self.server = server
self.handshaken = False
self.header = ""
self.data = ""
# Serve this client
def feed(self, data):
# If we haven't handshaken yet
if not self.handshaken:
logging.debug("No handshake yet")
self.header += data
if self.header.find('\r\n\r\n') != -1:
parts = self.header.split('\r\n\r\n', 1)
self.header = parts[0]
if self.dohandshake(self.header, parts[1]):
logging.info("Handshake successful")
self.handshaken = True
# We have handshaken
else:
logging.debug("Handshake is complete")
# Decode the data that we received according to section 5 of RFC6455
recv = self.decodeCharArray(data)
# Send our reply
self.sendMessage(''.join(recv).strip());
# Stolen from http://www.cs.rpi.edu/~goldsd/docs/spring2012-csci4220/websocket-py.txt
def sendMessage(self, s):
"""
Encode and send a WebSocket message
"""
# Empty message to start with
message = ""
# always send an entire message as one frame (fin)
b1 = 0x80
# in Python 2, strs are bytes and unicodes are strings
if type(s) == unicode:
b1 |= TEXT
payload = s.encode("UTF8")
elif type(s) == str:
b1 |= TEXT
payload = s
# Append 'FIN' flag to the message
message += chr(b1)
# never mask frames from the server to the client
b2 = 0
# How long is our payload?
length = len(payload)
if length < 126:
b2 |= length
message += chr(b2)
elif length < (2 ** 16) - 1:
b2 |= 126
message += chr(b2)
l = struct.pack(">H", length)
message += l
else:
l = struct.pack(">Q", length)
b2 |= 127
message += chr(b2)
message += l
# Append payload to message
message += payload
# Send to the client
self.client.send(str(message))
# Stolen from http://stackoverflow.com/questions/8125507/how-can-i-send-and-receive-websocket-messages-on-the-server-side
def decodeCharArray(self, stringStreamIn):
# Turn string values into opererable numeric byte values
byteArray = [ord(character) for character in stringStreamIn]
datalength = byteArray[1] & 127
indexFirstMask = 2
if datalength == 126:
indexFirstMask = 4
elif datalength == 127:
indexFirstMask = 10
# Extract masks
masks = [m for m in byteArray[indexFirstMask : indexFirstMask+4]]
indexFirstDataByte = indexFirstMask + 4
# List of decoded characters
decodedChars = []
i = indexFirstDataByte
j = 0
# Loop through each byte that was received
while i < len(byteArray):
# Unmask this byte and add to the decoded buffer
decodedChars.append( chr(byteArray[i] ^ masks[j % 4]) )
i += 1
j += 1
# Return the decoded string
return decodedChars
# Handshake with this client
def dohandshake(self, header, key=None):
logging.debug("Begin handshake: %s" % header)
# Get the handshake template
handshake = self.handshake
# Step through each header
for line in header.split('\r\n')[1:]:
name, value = line.split(': ', 1)
# If this is the key
if name.lower() == "sec-websocket-key":
# Append the standard GUID and get digest
combined = value + MAGICGUID
response = base64.b64encode(combined.digest())
# Replace the placeholder in the handshake response
handshake = handshake % { 'acceptstring' : response }
logging.debug("Sending handshake %s" % handshake)
self.client.send(handshake)
return True
def onmessage(self, data):
#logging.info("Got message: %s" % data)
self.send(data)
def send(self, data):
logging.info("Sent message: %s" % data)
self.client.send("\x00%s\xff" % data)
def close(self):
self.client.close()
# WebSocket server implementation
class WebSocketServer(object):
# Constructor
def __init__(self, bind, port, cls):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((bind, port))
self.bind = bind
self.port = port
self.cls = cls
self.connections = {}
self.listeners = [self.socket]
# Listen for requests
def listen(self, backlog=5):
self.socket.listen(backlog)
logging.info("Listening on %s" % self.port)
# Keep serving requests
self.running = True
while self.running:
# Find clients that need servicing
rList, wList, xList = select(self.listeners, [], self.listeners, 1)
for ready in rList:
if ready == self.socket:
logging.debug("New client connection")
client, address = self.socket.accept()
fileno = client.fileno()
self.listeners.append(fileno)
self.connections[fileno] = self.cls(client, self)
else:
logging.debug("Client ready for reading %s" % ready)
client = self.connections[ready].client
data = client.recv(4096)
fileno = client.fileno()
if data:
self.connections[fileno].feed(data)
else:
logging.debug("Closing client %s" % ready)
self.connections[fileno].close()
del self.connections[fileno]
self.listeners.remove(ready)
# Step though and delete broken connections
for failed in xList:
if failed == self.socket:
logging.error("Socket broke")
for fileno, conn in self.connections:
conn.close()
self.running = False
# Entry point
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s")
server = WebSocketServer("localhost", 8000, WebSocket)
server_thread = Thread(target=server.listen, args=[5])
server_thread.start()
# Add SIGINT handler for killing the threads
def signal_handler(signal, frame):
logging.info("Caught Ctrl+C, shutting down...")
server.running = False
sys.exit()
signal.signal(signal.SIGINT, signal_handler)
while True:
time.sleep(100)
It appears that you've named your own file socket.py, so when you import socket, you're not getting the system library (it's just re-importing the file you're currently in - which has no AF_INET symbol). Try renaming your file something like mysocket.py.
Even after changing the file name, if you are running the python from the terminal.
(you may get the same error)
Kindly
rm -rf socket.pyc
(previously compiled bytecode)
I had the same problem, I was literally stuck here for hours, tried re installing it a million times, but found the solution.
1) Make sure the file name is not socket.py,
2) Change the directory, it will not work in the home directory due to some permission issues.
If you have by anychance saved the file as socket.py, do not copy the same file or rename it to something else, the problem will persist.
What I advice you to do is, open a new folder in a different directory, write a simple socket code which involved AF_INET. Try to run it. It should work.
Issue can be that you have a file or Cache name socket.py or socket.pyc
rm -rf socket.py
rm -rf socket.pyc
Hopefully this will resolve your import issue. Gud Luck
enter the current working directory
and remove the files named 'socket.py' and 'socket.pyc'