需要有关 Python 套接字编程的帮助(初学者)



我正在学习套接字编程和python。我需要创建一个向服务器发送命令的客户端(列出或获取)。 然后,服务器验证该命令。 我的客户端程序可以显示"列表"或"获取",但是当我输入其他内容时,它不会显示错误消息。
此外,它只工作一次;当我在收到服务器的回复后输入不同的命令时,它给了我以下错误:

回溯(最近一次调用): 文件"fclient.py",第 49 行,在 client_socket.send(命令) 文件"/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py",第 170 行,_dummy 引发错误(EBADF,"错误的文件描述符")

我完全迷失了。在客户端程序中获取命令行输入并将其发送到服务器并要求服务器验证命令行参数的最佳方法是什么? 有人可以看看并指出我正确的方向吗?非常感谢您的帮助。

Client.py

import socket   #for sockets
import sys      #for exit
command = ' '
socksize = 1024
#return a socket descriptor which can be used in other socket related functions
#properties: address family: AF_INET (IP v4)
#properties: type: SOCK_STREAM (connection oriented TCP protocol)
try:
    #create an AF_INET, STREAM socket (TCP)
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:               #error handling
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ', Error message: ' + msg[1]
    sys.exit();
print 'Socket Created'
#Get the IP address of the remote host/url
#connect to IP on a certain 'port' using the connect
#host = 'flip3.engr.oregonstate.edu'
#port = 30021
#host = 'www.google.com'
#port = 80
host = ''       #symbolic name meaning the local host
port = 8888     #arbitrary non-privileged port
try:
    remote_ip = socket.gethostbyname(host)
except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Existing'
    sys.exit()
print 'IP address of ' + host + ' is ' + remote_ip
#Connect to remote server
client_socket.connect((remote_ip, port))
print 'Socket Connected to ' + host + ' on ip ' + remote_ip

#Send some data to remote server
while True:
    print 'Enter a command: list or get <filename>'
    command = raw_input()
    if command.strip() == 'quit':
        break
    client_socket.send(command)
    data = client_socket.recv(socksize)
    print data
#Close the socket
client_socket.close()

Server.py

import socket
import sys
from thread import *
#HOST = 'flip3.engr.oregonstate.edu' #symbolic name meaning all available interfaces
#PORT = 30021
HOST = ''
PORT = 8888
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
try:
    server_socket.bind((HOST, PORT))    #bind to a address(and port)
except socket.error, msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()
print 'Socket bind complete'
#put the socket in listening mode
server_socket.listen(10)     #maximum 10 connections
print 'TCP Server Waiting for client on port 30021'
#wait to accept a connection - blocking call
client, addr = server_socket.accept()
#display client information
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#keep talking with the client
while 1:
    #Receiving from client
    data = client.recv(1024)
    if (data == 'list' or data == 'get'):
        reply = 'receive: ' + data
        client.send(reply)
        break;
    else:
        reply = 'wrong command'
        client.send(reply)
client.close()

第一个问题是你在循环关闭客户端套接字,在收到对第一个命令的回复后关闭它。将关闭套接字移出循环,并引入退出条件以退出循环:

#Connect to remote server
client_socket.connect((remote_ip, port))
print 'Socket Connected to ' + host + ' on ip ' + remote_ip
#Send some data to remote server
while True:
    print 'Enter a command: list or get <filename>'
    command = raw_input()
    if command.strip() == 'quit':
        break
    client_socket.send(command)
    data = client_socket.recv(socksize)
    print data
# Close the socket
client_socket.close()

你在服务器端做类似的事情:你尝试在每次迭代时重新打开侦听套接字。将此部分也移出循环:

#wait to accept a connection - blocking call
client, addr = server_socket.accept()
#display client information
print 'Connected with ' + addr[0] + ':' + str(addr[1])

命令解析不起作用的原因是因为以下语句:

if (data == 'list' or 'get'):

你在这里想写的是

if (data == 'list' or data == 'get'):

第一个表达式的计算结果如下所示:

  • data == 'list'吗?
  • 如果是,则该子表达式的计算结果为 True,因此是a or b将返回的内容。
  • 如果没有,则选择要or的第二个操作数,即字符串'get'
  • or表达式的结果现在将由 if 语句隐式转换为布尔值:
  • 案例 1:True已经True
  • 情况 2:转换为布尔值的非空字符串的计算结果也为 True

因此,您的if语句将始终计算为True,这就是您的命令解析不起作用的原因。

if (data == 'list' or data == 'get'):

以更好的形式,我建议使用

if (data.strip() in ('list'  'get')):

最后,您应该将套接字代码包装在try..finally中,以确保套接字始终关闭,即使发生KeyboardInterrupt等异常:

try:
    #keep talking with the client
    while 1:
        #Receiving from client
        data = client.recv(1024)
        if (data.strip() in ('list'  'get')):
            reply = 'receive: ' + data
            client.send(reply)
        else:
            reply = 'wrong command'
            client.send(reply)
except KeyboardInterrupt:
    print "Exiting gracefully."
finally:
    server_socket.close()

finally子句在所有情况下都会执行 - 无论是否发生了已处理或未处理的异常)

一个问题是你在 while 循环中关闭client_socket。在那之后,client_socket.send()将不再起作用。 至少有两种方法可以解决此问题:

  1. client_socket.connect()移动到您的 while 循环中。
  2. 摆脱client_socket.close(),并将server_socket.accept()移动到 Server.py 中的 while 循环上方。

有更复杂的选项涉及select()或其他方法,但上面的两个项目之一现在应该可以让你通过。

最新更新