客户端收到一个窗口为 0 的包怎么处理

转载:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=28811518&id=5603324

调整窗口大小:
当TCP堆 栈接收到数据的时候,生成一个确认信息并以回复的方式发送,但是放置在接收端缓存中的数据并不总是立即被处理。当服务器忙于处理从多个客户端接收的报文, 服务器很有可能因为清理缓存而变得缓慢,无法腾出空间接收新的数据,如果没有流控,则可能会造成丢包和数据损坏。好在,接收窗口所设定的速率无法使服务器 正常处理数据时,能够调整接收窗口大小。通过减小返回给发送端的ACK报文的TCP头窗口大小值来实现。如下图所示:

上图中,服务器初始窗口大小为5000字节。客户端发送2000字节,之后又发送了2000字节,缓冲区中只有1000字节可用。服务器意识到缓冲 区正在快速填满,它知道如果数据继续以此速率传输,很快会有报文丢失。为了防止报文丢失,服务器发送确认信息给客户端,更新窗口大小为1000字节。结 果,客户端减少数据发送,服务器以可以接受的速率处理缓存内容,即保持数据流以稳定的速率传输。
调整窗口大小在两个方向都是可行的。当服务器能够更加快速的处理报文时,它会发送一个较大窗口的ACK报文

零窗口暂停数据流:

某些情况下,服务器无法再处理从客户端发送的数据。可能是由于内存不足,处理能力不够,或其他原因。这可能会造成数据被丢弃以及传输暂停,但接收窗口能够帮助减小负面影响。
上述情况发生时,服务器会发送窗口为0的报文。当客户端接收到此报文时,它会暂停所有数据传输,但会保持与服务器的连接以传输探测(keep- alive)报文。探测报文在客户端以稳定间隙发送,以查看服务器接收窗口状态。一旦服务器能够再次处理数据,将会返回非零值窗口大小,传输会恢复。下图 示例了零窗口通知过程

服务器初始接收数据窗口为5000字节大小。从客户端接收4000字节数据之后,服务器负载变得非常繁重,无法继续处理客户端任何数据。服务器于是发送窗 口大小值为0的报文。客户端暂停数据传输并发送一个探测报文。探测报文之后,服务器回复以告知客户端现在可以接收数据的报文,以及窗口大小为1000字 节。客户端恢复传送数据。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您编写这样的程序。因为您没有指定编程语言,我将使用Python语言来实现。 首先,我们需要安装Python的图形用户界面工具Tkinter。在Windows下,打开命令提示符,输入以下命令来安装: ``` pip install tkinter ``` 接下来,我们编写服务器端程序。服务器端程序需要监听一个端口,并在有客户请求时显示客户端IP地址、端口和收到的数据。 ``` python import socket import threading import tkinter as tk class Server: def __init__(self, host, port): self.host = host self.port = port self.clients = [] self.running = False self.window = tk.Tk() self.window.title('服务器') self.listbox = tk.Listbox(self.window, width=50) self.listbox.pack(padx=10, pady=10) self.start_button = tk.Button(self.window, text='启动', command=self.start) self.start_button.pack(pady=10) self.stop_button = tk.Button(self.window, text='停止', command=self.stop, state='disabled') self.stop_button.pack(pady=10) self.window.mainloop() def start(self): self.running = True self.start_button.config(state='disabled') self.stop_button.config(state='normal') self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.bind((self.host, self.port)) self.socket.listen() self.thread = threading.Thread(target=self.listen_for_clients) self.thread.start() def stop(self): self.running = False self.socket.close() def listen_for_clients(self): while self.running: client_socket, client_address = self.socket.accept() self.clients.append(client_socket) threading.Thread(target=self.handle_client, args=(client_socket, client_address)).start() def handle_client(self, client_socket, client_address): while self.running: try: data = client_socket.recv(1024).decode('utf-8') if data: self.listbox.insert(tk.END, f'{client_address[0]}:{client_address[1]}: {data}') except: break self.clients.remove(client_socket) client_socket.close() server = Server('127.0.0.1', 8000) ``` 在代码中,我们定义了一个Server类,该类含以下方法: - `__init__(self, host, port)`:构造方法,初始化主机和端口,并创建GUI界面。 - `start(self)`:启动服务器,开始监听端口。 - `stop(self)`:停止服务器,关闭socket连接。 - `listen_for_clients(self)`:监听客户端连接并创建线程处理客户端请求。 - `handle_client(self, client_socket, client_address)`:处理客户端请求。 在`__init__`方法中,我们创建了一个Tkinter窗口,并添加了两个按钮(启动和停止按钮)和一个列表框用于显示客户端IP地址、端口和收到的数据。 在`start`方法中,我们创建了一个socket对象,并调用`listen`方法开始监听端口。然后启动一个新线程来监听客户端连接。 在`listen_for_clients`方法中,我们使用一个while循环来监听客户端连接,当有新的客户端连接时,我们将客户端socket对象添加到`self.clients`列表中,并启动一个新线程来处理客户端的请求。 在`handle_client`方法中,我们使用一个while循环来监听客户端发送的数据,当有数据到达时,我们将数据显示在列表框中。如果客户端断开连接或发生异常,我们将客户端socket对象从列表中移除,并关闭socket连接。 接下来,我们编写客户端程序。客户端程序需要连接到服务器端,并发送数据。我们可以使用Python的socket模块来实现。 ``` python import socket import tkinter as tk class Client: def __init__(self, host, port): self.host = host self.port = port self.window = tk.Tk() self.window.title('客户端') self.input_text = tk.Entry(self.window, width=50) self.input_text.pack(padx=10, pady=10) self.send_button = tk.Button(self.window, text='发送', command=self.send_message) self.send_button.pack(pady=10) self.window.mainloop() def send_message(self): message = self.input_text.get() self.input_text.delete(0, tk.END) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((self.host, self.port)) s.sendall(message.encode('utf-8')) client = Client('127.0.0.1', 8000) ``` 在代码中,我们定义了一个Client类,该类含以下方法: - `__init__(self, host, port)`:构造方法,初始化主机和端口,并创建GUI界面。 - `send_message(self)`:发送消息到服务器端。 在`__init__`方法中,我们创建了一个Tkinter窗口,并添加了一个文本框和一个发送按钮。当用户点击发送按钮时,我们将文本框中的内容发送到服务器端。 在`send_message`方法中,我们创建了一个socket对象,并调用`connect`方法连接到服务器端。然后将消息发送到服务器端。 现在,我们可以在两台计算机上分别运行服务器端和客户端程序,并进行通信。当客户端发送数据时,服务器端将显示客户端IP地址、端口和收到的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值