网络编程问题

时间:2011-01-14 10:37:36

标签: python networking

我编写了一个客户端服务器程序,服务器将程序发送到客户端,客户端执行收到的程序。在这种情况下,它是OpenGL中的线条绘制程序。问题在于,在运行服务器和客户端时,整个程序,即有时将程序发送到服务器和客户端执行,但有时不执行。客户端连接然后卡住了。该程序也没有停止。在我的朋友系统中同样的工作,但在我的它只有时工作(大多数时候它不会)。可能是什么原因?我错过了什么吗?

我的服务器代码:

from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
import sys
import threading
import os
import socket

class ClientThread ( threading.Thread ):
 # Override Thread's __init__ method to accept the parameters needed:
 def __init__ ( self, channel, details ):
  self.channel = channel
  self.details = details
  threading.Thread.__init__ ( self )

 #Codes to be executed when thread is executed:
 def run ( self ):
  a1=self.channel.recv(1024)
  print "client says:"+a1
  print 'Received connection:', self.details [ 0 ]
  finp = open("stringcheck.py","r")
  #self.channel.send("#start\n")
  info = finp.readlines() 
  for record in info:
   self.channel.send(record)
  #self.channel.send(info)
  self.channel.send("#p") 


server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
server.bind ( ( '127.0.0.1', 4500) )
#Listens for connections made to socket.
#Specifies maximum number of queued connection.
server.listen ( 5 )
while True:
 channel, details = server.accept()
 #Create an instance of thread class and call its start method.
 ClientThread ( channel, details ).start()

我的客户代码:

from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
OpenGL.ERROR_CHECKING=False
import os
import socket
import threading
import thread
import subprocess

class ConnectionThread( threading.Thread ):

 def run ( self ):

  client = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
  client.connect( ( '127.0.0.1', 9000) )
  client.send("connected")
  a=client.recv(1024)
  b=a
  f=1 
  while f:
   print 'sdf'
   a = client.recv(1024)
   print 'qwe'
   if a=="#p":
    f=0
    break
   b+=a
  print b
  exec(b)

  client.close()
ConnectionThread().start()
 from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
OpenGL.ERROR_CHECKING=False
import os
import socket
import threading
import thread
import subprocess

class ConnectionThread( threading.Thread ):

 def run ( self ):

  client = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
  client.connect( ( '127.0.0.1', 9000) )
  client.send("connected")
  a=client.recv(1024)
  b=a
  f=1 
  while f:

   a = client.recv(1024)
   print 'qwe'
   if a=="#p":
    f=0
    break
   b+=a
  print b
  exec(b)

  client.close()
ConnectionThread().start()

1 个答案:

答案 0 :(得分:4)

<强> 1。 TCP套接字是流 (数据包是实现细节)

优化网络堆栈以限制发送的数据包数量。因此,当您在套接字上多次调用send()时,网络堆栈可以在多个数据包之间自由拆分(或不拆分)数据。

在运行在真实网络上的计算机上,这比环回连接慢得多,如果您在呼叫send()时仍有一个等待发送的数据包,则新数据将附加到等待包。在接收端,网络堆栈可以自由合并多个数据包(从套接字接收的数据被缓冲),以便立即为您提供数据。

所以,在服务器中,你写:

for record in info:
    self.channel.send(record)
self.channel.send("#p") 

最后一个数据包可能包含程序结束和终结符,连接在一起。 在客户端:

a = client.recv(1024)
if a=="#p":
    break

终结符可能不在接收数据包的开头,并且可能不是数据包中存在的唯一字符。如果是这种情况,那么你没有检测到终结符,不要退出循环,再次调用recv(),并在此处停止,因为recv()是阻塞调用,服务器将不再发送任何数据

因此,您必须选择另一种了解服务器何时完成数据发送的方式。有很多可能性:

  • 第一个明显的方法是在客户端上,而不是if a=="#p":,写if a.endswith("#p"):。这可以纠正代码中存在的问题
  • 您也可以选择在发送之前首先发送程序的长度。客户端读取长度,然后读取该字符数并停止
  • 服务器完成发送程序后可以简单地关闭连接。在recv()返回空字符串时,您在客户端检测到连接已关闭,然后您知道已收到该程序。不幸的是,如果服务器在发送整个程序之前崩溃,您将在客户端上执行一个不完整的程序

有无数其他可能来纠正这个问题...

<强> 2。你的接收逻辑是错误的

现在,仔细查看接收逻辑(编辑代码以删除不相关的行)

1. a=client.recv(1024)
2. b=a
3. f=1 
4. while f:
5.     a = client.recv(1024)
6.     if a=="#p":
7.         f=0
8.         break
9.     b+=a

在这里,您首先等待一些数据(第1行)。然后你输入你的while循环(第4行),然后再等一些数据(第5行)!

recv()是一个阻塞调用:这意味着在有一些数据要返回或连接关闭之前它不会返回。如果服务器发送少于1024个字节(包括终结符),则会收到第1行(包括终结符)上的所有内容,但仍在第5行等待更多数据...

请注意,测试中仍然存在错误:如果分隔符在2 recv()次调用之间分配(如果程序长度恰好为1023字节,则会发生这种情况),a.endswith('#p')永远不会计算为{ {1}}。

所以这是一个正确的接收逻辑,一旦收到一些数据就会测试终结器:

True

请注意,通过删除不必要的变量可以大大简化:

a = client.recv(1024)    
b = a
f = 1 
while f:
    if b.endswith("#p"):
        f=0
        break
    a = client.recv(1024)
    b += a

第3。正确释放代码中使用的资源

我一开始并没有强调这一点,但你应该始终正确地关闭你的连接!

创建了python语言,只要持有它的变量不再被引用(在你的情况下,当它超出范围时),就会隐式关闭连接。但是,明确地关闭它将清楚表明您希望连接关闭的点。

某些实现可能会决定将资源的发布推迟到以后(Jython用户可能遇到过这个问题),保持连接打开...这没有问题,但是可能会在以后的程序中导致奇怪的行为发展成为功能更完善的产品。