首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >网络编程问题

网络编程问题
EN

Stack Overflow用户
提问于 2011-01-14 18:37:36
回答 1查看 480关注 0票数 2

我已经编写了一个客户端服务器程序,其中服务器向客户端发送程序,客户端执行接收到的程序。在本例中,它是OpenGL中的线条绘制程序。问题是,在运行服务器和客户端时,整个程序,即将程序发送到服务器和客户端,有时会执行,但有时不会执行。客户端连接起来,然后就卡住了。这个程序不会停止,在我的朋友系统中也是一样的,但在我的系统中,它只是偶尔起作用(大多数时候是不起作用的)。可能的原因是什么?我是不是遗漏了什么?

我的服务器代码:

代码语言:javascript
复制
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()

我的客户端代码:

代码语言:javascript
复制
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()
EN

回答 1

Stack Overflow用户

发布于 2011-01-14 18:51:53

TCP socket是一个流(数据包是实现细节)。

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

在实际网络上运行的计算机上,如果在调用send()时仍有一个数据包等待发送,则新数据将被附加到等待的数据包。在接收端,网络堆栈可以自由地合并多个数据包(从套接字接收的数据被缓冲),以便一次显示数据。

因此,在服务器中,您可以这样写:

代码语言:javascript
复制
for record in info:
    self.channel.send(record)
self.channel.send("#p") 

最后一个分组可以包含连接在一起的节目的结尾和终止符。在客户端:

代码语言:javascript
复制
a = client.recv(1024)
if a=="#p":
    break

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

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

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

上执行不完整的程序

有无数其他的可能性来纠正这个问题……

2.你的接收逻辑是错误的

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

代码语言:javascript
复制
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行上的更多数据...

请注意,您的测试中仍然存在一个bug :如果分隔符被分成两个recv()调用(如果程序的长度正好是1023个字节,就会发生这种情况),a.endswith('#p')的计算结果永远不会是True

所以这里是一个正确的接收逻辑,它在接收到一些数据后立即测试终结器:

代码语言:javascript
复制
a = client.recv(1024)    
b = a
f = 1 
while f:
    if b.endswith("#p"):
        f=0
        break
    a = client.recv(1024)
    b += a

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

代码语言:javascript
复制
b = client.recv(1024)
while not b.endswith("#p"):
    b += client.recv(1024)

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

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

创建python语言的目的是,一旦保存连接的变量不再被引用(在您的例子中,当它超出范围时),连接就会隐式关闭。但是,显式地关闭它将清楚地表明您希望在哪个点关闭连接。

一些实现可能决定将资源的发布推迟到以后的时间(Jython用户可能已经遇到了这个问题),使连接保持打开状态……这不是问题,但当您的程序发展到功能更完整的产品时,可能会导致稍后出现奇怪的行为。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4690155

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档