为什么服务器不回复部分SYN_ACK报文:(back_log)

最近遇到一个问题,就是向服务器发送报文。(发送一个报文建立一次TCP连接,报文是并发发送的)、发送了10几个报文之后,Java的客户端开始抛出:

java.net.SocketTimeoutException: connect timed out

    at java.net.PlainSocketImpl.socketConnect(Native Method)

    at java.net.PlainSocketImpl.doConnect(UnknownSource)

    atjava.net.PlainSocketImpl.connectToAddress(Unknown Source)

    at java.net.PlainSocketImpl.connect(UnknownSource)

    at java.net.SocksSocketImpl.connect(UnknownSource)

    at java.net.Socket.connect(Unknown Source)

    at Client.sendMessage(Client.java:43)

    at Client.run(Client.java:28)

    at java.lang.Thread.run(Unknown Source)

剩下的报文无法再正常发送了。

以下是我客户端代码的简化版。

public class Client extends Thread{
		 public static void main (String args[]) {
		
		 int n = 20;
		 for(int i=0;i<n;i++) {	  
			 new Thread(new Client()).start();
		 }	 
		 
	 }
	 
	 @Override
	public void run() {
		 String ip = "192.168.0.12";
		 int  port = 9136;	 
		 sendMessage(ip, port);
	}


	public void sendMessage(String ip, int port) { 
		 
		 Socket clientSocket = new Socket();
		 SocketAddress serverAddress =  new InetSocketAddress(ip, port);
		 Writer writer = null;
		 /*
		  * 指定服务器的IP地址和通讯端口
		  */
		 int timeout  = 50;
		 try {
			 System.out.println("client connect to server");
			 clientSocket.connect(serverAddress,timeout);
			 System.out.println("Connect succeed");
			 writer = new OutputStreamWriter(clientSocket.getOutputStream());
			 writer.write("hello server");
			 writer.flush();			 
			 writer.close();
			 clientSocket.close();
		     System.out.println("connection closed");
		}catch(SocketTimeoutException e) {	
			e.printStackTrace();
		    System.out.println("connect to server failed!!!");
		} catch (IOException e) {
		
			e.printStackTrace();
		}finally {
	    	try {
		    	if(writer!=null) {
					writer.close();
		    	 }
		    	if(clientSocket!=null) {
		    		clientSocket.close();
		    	}

			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		 
	 }
}

<p>在最开始我怀疑是客户端代码的问题:</p><p>       clientSocket.connect(serverAddress,timeout);把函数中timeout的值设大了之后,报文书能增长到30几个左右,但是后边的的TCP连接还是抛出了上文中的异常。</p><p>经过对服务器端口进行抓包分析。发现抓包发现服务器端有收到客服端发送的TCP三次握手的SYN报文,但是后边的连接的SYN报文。服务器端好像就是置之不理的感觉。就是不回复SYN_ACK。所以导致client端的socket抛出<u><span style="color:navy;">SocketTimeoutException</span><span style="color:navy;">。</span></u></p><p> 当我在网上搜索为什么服务器不回复SYN报文SYN_ACK时候。搜到以下一片文章:</p><p><a target=_blank href="http://serverfault.com/questions/235965/why-would-a-server-not-send-a-syn-ack-packet-in-response-to-a-syn-packet%EF%BC%8C%E5%AF%B9linux%E7%9A%84%E7%B3%BB%E7%BB%9F%E5%8F%82%E6%95%B0%E5%81%9A%E4%BA%86%E4%BF%AE%E6%94%B9%EF%BC%8C%E9%97%AE%E9%A2%98%E4%BB%8D%E7%84%B6%E6%B2%A1%E6%9C%89%E5%BE%97%E5%88%B0%E8%A7%A3%E5%86%B3%E3%80%82"><span style="color:#2A5685;">http://serverfault.com/questions/235965/why-would-a-server-not-send-a-syn-ack-packet-in-response-to-a-syn-packet</span></a></p><p>根据文章中,对服务的 tcpwindows scaling 和tcptimestamps参数进行了修改。发现还是不起作用。</p><p> 到底是什么限制了tcp连接:</p><p>怀疑是服务器的原因。服务器在并发的时候处理不过来。所以拒绝新来的来接。做了以下工作:</p><p>在客户端并发发送报文的时候,用top命令才看服务器的CPU占用率。根本没过1%。排除服务器处理不过来的原因。</p><p>查看此时TCP端口的暂用情况:对9136端口的占用ESTABLISH的10几个,SYN_RECV的2个作用。占用情况也不是很高。</p><p> 最后能想到的原因就是服务器程序的原因了。</p><p>在对服务器程序代码的检查中发现back_log这样一个参数:被设置成了5.</p><p>Back_log的定义为:</p><p><span style="background:#F0F3FA;">该参数规定了</span><span style="background:#F0F3FA;">TCP</span><span style="background:#F0F3FA;">层可以容纳的连接请求队列长度(应用层尚未进行处理),以下是</span><span style="background:#F0F3FA;">back_log</span><span style="background:#F0F3FA;">的限制说明。</span></p><p align="center"></p><p>摘自:http://www.2cto.com/os/201207/139524.html</p><p>由于同时并发数有30几个TCP链接,back_log被设置成5了。当ESTABLISHED队列和SYN_RECV队列之和超过了5时。后边新来的连接被没有多余的空间可以放置。所以直接被丢弃了。由于我的客户端程序clientSocket.connect(serverAddress,timeout)中的timeout时间被设置成50ms。50ms内没有收到服务器的SYN_ACK时候,抛出timeoutexception。如果把timeout参数设置成8s.情况又不一样。第一次发送的SYN报文被丢弃了。客户端会在间隔1s、2s、4s的时候再次尝试。可能恰好back_log队列已满,这些SYN报文也可能被丢弃。但是增大了服务器接收的概率。</p><p>当然最根本的原因还是back_log的参数设置不够大。</p><p>总结:</p><p>传入连接指示(对连接的请求)的最大队列长度被设置为 <code>backlog</code> 参数。如果队列满时收到连接指示,则拒绝该连接。<span style="color:red;">并且不会给出任何回复</span>,不回送rst,只是单纯的丢弃了客户端的SYN报文。</p><p>服务器要支持较大的并发量。Backlog参数的设置不能太小。</p>




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值