我在执行python作业时遇到问题,想向社区寻求指导。我仅将 socket模块和 argparse 模块用于此分配。我创建了一个socketserver.py文件和一个socketclient.py文件。服务器和客户端之间的连接良好。现在,分配的目的是客户使用 argparse 发送彩票游戏类型,彩票数和每彩票行数。例如。 socketclient.py的语法为python3 -t Lotto_Max -n 2 -l 2.门票游戏的输出,门票类型和每张门票的行数在服务器上正确显示。但是,它们有时无法在客户端正确显示,并且此刻确实卡住了。这是我的以下代码。...
```socketserver.py code```
import socket
from random import sample
def main():
host = input("Please specify an IP address for this server's socket\t")
port = int(input('Please speciy a port number above 1024 for this socket.\t'))
kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
kulmiye.bind((host, port))
except socket.error as egeh:
print('Socket bind failed. Error Code : ' + str(egeh[0]) + ' Message ' + egeh[1])
print('Socket bind accomplished...\n')
print("Listening for an incoming connection...")
kulmiye.listen()
conn, addr = kulmiye.accept()
print('Connected with ' + addr[0] + ':' + str(addr[1]))
while True:
server_data = conn.recv(1024).decode("utf-8")
game_data = server_data.split(",")
if not server_data:
break
if game_data[0] == "Lotto_Max":
nval = int(game_data[1])
lval = int(game_data[2])
for nval in range(nval):
for i in range(lval):
numbers = sample(range(1, 50), 7)
numbers.sort()
sortedd = str(numbers)
print(sortedd)
print("--------------------")
conn.sendall(sortedd.encode("utf-8"))
#conn.sendall(bytes(str(numbers),'utf-8'))
liners = "-----------------------"
conn.sendall(liners.encode("utf-8"))
print("From Client: " + str(game_data))
conn.sendall(b'goodbye')
# server_data = input('#\t')
break
else:
conn.close()
if __name__ == '__main__':
main()
```socketclient.py code```
import socket
import argparse
def client():
host = input("Please specify the server's IP you want to connect to\t")
port = int(input("Please specify the server's port you want to connect to\t"))
kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
kulmiye.connect((host, port))
# client_data = input("#\t")
# while True:
# client_data = input()
# if client_data == 'quit':
# kulmiye.close()
# sys.exit()
# if len(str.encode(client_data)) > 0:
# kulmiye.sendall(str.encode(client_data))
# server_response = str(kulmiye.recv(1024), "utf-8")
# print(server_response, end = " ")
kulmiye.sendall(bytes(tvar.encode("utf-8")))
kulmiye.sendall(bytes(','.encode("utf-8")))
kulmiye.sendall(bytes(str(nval).encode("utf-8")))
kulmiye.sendall(bytes(','.encode("utf-8")))
kulmiye.sendall(bytes(str(lval).encode("utf-8")))
server_data = kulmiye.recv(1024).decode("utf-8")
while server_data != 'goodbye':
server_data = kulmiye.recv(1024).decode("utf-8")
print('Server: \n' + server_data)
# client_data = input("#\t")
if not server_data:
break
kulmiye.close()
# this code block serves to give the user the ability to play lotto max
# with the amount of tickets and lines per ticket they would like
# Using the argparse module to allow the user to input command-line interfaces
parser = argparse.ArgumentParser(description='Welcome to OLG Gaming.')
parser.add_argument(
'-t',
type=str,
help="Pick the lottery you want to play",
required=True)
parser.add_argument(
'-n',
type=int,
help="Pick the amount of lottery tickets you want to play",
required=True)
parser.add_argument(
'-l',
type=int,
help="Pick the amount of lines you would like to play",
required=True)
# parser.add_argument('-o', type = str, help = "This is optional", required = False)
# parse_args will convert the argument strings into objects and will get
# stored in the cmdargs variable
cmdargs = parser.parse_args()
tvar = cmdargs.t # the t string argument that gets parsed into an object will get stored into a variable called tvar
# the n integer argument that gets parsed into an object will get stored
# into a variable called nval
nval = int(cmdargs.n)
# the l integer argument that gets parsed into an object will get stored
# into a variable called lval
lval = int(cmdargs.l)
if __name__ == "__main__":
client()
```code```
python3 socketserver.py
python3 socketclient.py -t Lotto_Max -n 1 -l 1
当客户端与服务器之间建立连接时,服务器会接收客户端输入并在其末端打印游戏类型(Lotto_Max),票证数量和每张票证的行数
服务器将输出结果,例如
但是,客户不会无限期收到它。通常,它会在大约25%的时间内得到解决,但我不确定为什么
答案 0 :(得分:0)
服务器中的一个问题是
server_data = conn.recv(1024).decode("utf-8")
conn.recv(1024)
可以接收从0(关闭的连接)到1024的任意数量的字节。上面的行假定每次都接收到整个消息,但是如果失败,则仅获取部分消息。在下面,我修改了您的代码,以便服务器可以一次处理多个客户端连接,并且客户端将一遍又一遍地连接/断开连接以加快故障发生:
服务器:
import socket
from random import sample
def main():
host = ''
port = 4444
kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
kulmiye.bind((host, port))
print('Socket bind accomplished...\n')
print("Listening for an incoming connection...")
kulmiye.listen()
while True:
conn, addr = kulmiye.accept()
print('Connected with ' + addr[0] + ':' + str(addr[1]))
with conn:
server_data = conn.recv(1024).decode("utf-8")
print(f'server_data={server_data}')
game_data = server_data.split(",")
print("From Client: " + str(game_data))
if server_data:
if game_data[0] == "Lotto_Max":
nval = int(game_data[1])
lval = int(game_data[2])
for nval in range(nval):
for i in range(lval):
numbers = sample(range(1, 50), 7)
numbers.sort()
sortedd = str(numbers)
print(sortedd)
print("--------------------")
conn.sendall(sortedd.encode("utf-8"))
liners = "-----------------------"
conn.sendall(liners.encode("utf-8"))
conn.sendall(b'goodbye')
if __name__ == '__main__':
main()
客户:
import socket
import argparse
def client():
host = 'localhost'
port = 4444
kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
kulmiye.connect((host, port))
kulmiye.sendall(bytes(tvar.encode("utf-8")))
kulmiye.sendall(bytes(','.encode("utf-8")))
kulmiye.sendall(bytes(str(nval).encode("utf-8")))
kulmiye.sendall(bytes(','.encode("utf-8")))
kulmiye.sendall(bytes(str(lval).encode("utf-8")))
server_data = kulmiye.recv(1024).decode("utf-8")
while server_data != 'goodbye':
server_data = kulmiye.recv(1024).decode("utf-8")
print('Server: \n' + server_data)
# client_data = input("#\t")
if not server_data:
break
kulmiye.close()
tvar = 'Lotto_Max'
nval = 1
lval = 1
if __name__ == "__main__":
while True:
client()
这是成功连接数百次后的结果。注意成功连接和失败连接之间的server_data
:
Connected with 127.0.0.1:12175
server_data=Lotto_Max,1,1
From Client: ['Lotto_Max', '1', '1']
[4, 7, 9, 12, 24, 31, 48]
--------------------
Connected with 127.0.0.1:12176
server_data=Lotto_Max,1,
From Client: ['Lotto_Max', '1', '']
Traceback (most recent call last):
File "C:\server.py", line 38, in <module>
main()
File "C:\server.py", line 24, in main
lval = int(game_data[2])
ValueError: invalid literal for int() with base 10: ''
conn.recv(1024)
没有收到完整的消息(没有得到最后的1
)。 TCP是一种字节流协议,没有消息边界的概念。您的代码负责调用recv()
并缓冲数据,直到收到完整的消息为止。您可以发送固定大小的消息并调用recv,直到有那么多字节为止,使用定点字节(例如换行符({\n
)终止消息,然后阅读直到收到定点为止,或者发送消息的大小首先是消息字节。
我不会为您解决此问题,因为它是一项任务,但提示socket.makefile
可以将套接字包装在类似文件的对象中,您可以在其中调用.read(n)
来精确读取{{ 1}}个字节(来自套接字),或n
个字节来读取.readline()
终止的行。
以下是我的答案的链接,它证明了这一点:https://stackoverflow.com/a/55840026/235698
TCP的流传输性质的另一个示例是在客户端。有时,它会打印:
\n
服务器中的单独行:
-----------------------
Server:
goodbye
Server:
-----------------------goodbye
Server:
Server:
-----------------------
Server:
goodbye
有时会被客户端中的单个conn.sendall(liners.encode("utf-8"))
conn.sendall(b'goodbye')
接收:
recv
同样,这是由于TCP的流式传输特性,并且没有消息边界。如果您发送的每行都以换行符结尾,则可以多次调用server_data = kulmiye.recv(1024).decode("utf-8")
直到检测到换行符,然后仅处理该行。
另一个说明此技术的答案在这里:https://stackoverflow.com/a/55186805/235698。
答案 1 :(得分:0)
谢谢Mark Tolonen的指导。我仍然需要复习如何处理TCP数据流。尽管如此,我还是可以通过大量的操作获得更理想的结果
conn.sendall
在我的嵌套for循环中。快乐的露营者!