socket closesocket,什么原因罗致的呢

18537人阅读
TIME_WAIT状态
如果服务端的Socket比客户端的Socket先关闭,会导致客户端出现TIME_WAIT状态,占用系统资源。
所以,必须等客户端先关闭Socket后,服务器端再关闭Socket才能避免TIME_WAIT状态的出现。
判断客户端Socket的关闭
最近试验发现,当客户端Socket关闭时,服务端的Socket会接收到0字节的通知。
private int Receive(StringBuilder sb)
&&&&int read = 0, total = 0;
&&&&if (_Client != null)
&&&&&&&&try
&&&&&&&&&&&&byte[] bytes = new byte[SIZE];
&&&&&&&&&&&&int available = _Client.A
&&&&&&&&&&&&do
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&read = _Client.Receive(bytes);//如果客户端Socket关闭,_Client会接受到read=0
&&&&&&&&&&&&&&&&total +=
&&&&&&&&&&&&&&&&if (read & 0)
&&&&&&&&&&&&&&&&&&&&sb.Append(_Server.DefaultEncoding.GetString(bytes, 0, read));
&&&&&&&&&&&&} while (read & 0 && total & available);
&&&&&&&&catch (SocketException)
&&&&&&&&&&&&CloseSocket();
&&&&if (_Server.TraceInConsole && total & 0)
&&&&&&&&Console.WriteLine("Receive:" + total + "======================================");
&&&&&&&&Console.WriteLine(sb.ToString());
&&&&return
利用0字节接收条件判断客户端Socket的关闭,开始执行服务端Socket关闭代码。
private void ThreadHandler()
&&&&if (_Server.TraceInConsole)
&&&&&&&&Console.WriteLine("Begin HttpRequest...");
&&&&&&&&while (true)
&&&&&&&&&&&&StringBuilder sb = new StringBuilder();
&&&&&&&&&&&&int receive = Receive(sb);
&&&&&&&&&&&&if (receive & 0)
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&_Server.ReadRequest(this, sb.ToString());
&&&&&&&&&&&&&&&&_Server.Response(this);
&&&&&&&&&&&&&&&&_Server.ResponseFinished(this);
&&&&&&&&&&&&}
&&&&&&&&&&&&else
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&TryCloseSocket();
&&&&&&&&&&&&}
&&&&&&&&&&&&if (_Client == null)
&&&&&&&&&&&&&&&&break;
&&&&catch (Exception ex)
&&&&&&&&if (_Server.TraceInConsole)
&&&&&&&&&&&&Console.WriteLine(ex.Message);
&&&&if (_Server.TraceInConsole)
&&&&&&&&Console.WriteLine("End HttpRequest.");
服务端Socket的关闭
如果直接调用Socket的Close方法会关闭得太快,可能导致客户端TIME_WAIT现象;而Thead.Sleep延时再调用Socket的Close方法也不理想。应该采用尝试向客户端发送数据,然后利用异常来关闭Socket,方法如下。
private void TryCloseSocket()
&&&&&&&&while (true)
&&&&&&&&&&&&Thread.Sleep(1500);
&&&&&&&&&&&&Send(HttpServer.BYTES_CRLF); //发送自定义的字节,如果客户端关闭出现SocketException,然后关闭服务端Socket
&&&&&&&&&&&&if (_Client == null)
&&&&&&&&&&&&&&&&break;
&&&&catch (SocketException)
&&&&&&&&CloseSocket();
private void CloseSocket()
&&&&if (_Client != null)
&&&&&&&&_Client.Shutdown(SocketShutdown.Both);
&&&&&&&&_Client.Close();
&&&&&&&&_Client = null;
&&&&&&&&if (_Server.TraceInConsole)
&&&&&&&&&&&&Console.WriteLine("Close socket.");
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:570902次
积分:7550
积分:7550
排名:第1967名
原创:160篇
转载:10篇
评论:219条
阅读:14224
文章:40篇
阅读:130523
文章:35篇
阅读:69159
文章:39篇
阅读:113443
(1)(2)(4)(1)(1)(2)(1)(1)(2)(1)(1)(1)(4)(2)(2)(3)(3)(7)(1)(1)(1)(1)(4)(4)(3)(1)(3)(3)(4)(6)(3)(7)(4)(4)(3)(4)(6)(6)(3)(2)(3)(3)(5)(2)(1)(3)(5)(3)(3)(2)(2)(3)(4)(5)(13)为什么我们在写socket的时候,server与client都要写上socket.close_百度知道非阻塞socket 什么时候close_百度知道Android(3)
在一个有关socket的程序中,客户端出现了 socket is closed异常,我百思不得其解,并没有关闭socket啊。
下面首先来分析一下这个异常出现的原因:该异常在客户端和服务器均可能发生。异常的原因是己方主动关闭了连接后(调用了Socket的close方法)再对网络连接进行读写操作。
而造成socket关闭常见的有以下两种:
1、调用了.close()方法关闭socket
2、关闭了输入输出流
下面来看一下我的错误代码
BufferedWriter bufferedWriter=null
bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()))
} catch (IOException e) {
Log.d("Client","BufferedWriter出错")
e.printStackTrace()
// 获得EditTex的内容
String text = mEditText.getText().toString()
Log.e("Client","即将发送的信息为:"+text)
Log.e("Client","haha")
// 发送数据
if (bufferedWriter != null) {
bufferedWriter.write(text+"\r\n")
bufferedWriter.flush()
bufferedWriter.close()
} catch (IOException e) {
Log.e("Client","发送数据出错")
e.printStackTrace()
Log.e("Client", "成功发送数据")
// 清空内容
mEditText.setText("")
Log.e("Client", "下面开始读取数据")
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(),"UTF-8"))
Log.e("Client","完毕")
String s=in.readLine()
Log.e("Client",s)
} catch (IOException e) {
Log.e("Client",e.getMessage())
可以看到在用write()方法传送完成后,又调用了bufferedWriter.close();正是因为这一行代码,导致socket closed。而下面BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(),"UTF-8"));因此出现异常
那么我们的解决方式是将bufferedWriter.close();下移到末尾处即可如下:
BufferedWriter bufferedWriter=null;
bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
} catch (IOException e) {
Log.d("Client","BufferedWriter出错");
e.printStackTrace();
String text = mEditText.getText().toString();
Log.e("Client","即将发送的信息为:"+text);
Log.e("Client","haha");
if (bufferedWriter != null) {
bufferedWriter.write(text+"\r\n");
bufferedWriter.flush();
} catch (IOException e) {
Log.e("Client","发送数据出错");
e.printStackTrace();
Log.e("Client", "成功发送数据");
mEditText.setText("");
Log.e("Client", "下面开始读取数据");
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(),"UTF-8"));
Log.e("Client","完毕");
String s=in.readLine();
Log.e("Client",s);
} catch (IOException e) {
Log.e("Client",e.getMessage());
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:3230次
排名:千里之外
原创:19篇
(2)(1)(4)(2)(4)(7)博客访问: 805865
博文数量: 1491
博客积分: 38
博客等级: 民兵
技术积分: 5827
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: 架构设计与优化
原文地址: 作者:
&&&&& & close函数原型如下:
&&&&& & int close(int sockfd);
&&&&& & 参数sockfd为套接字描述符,成功返回0,失败返回-1,错误码errno:EBADF表示一个非有效描述符;EINTER表示被信号中断;EIO表示一个IO错误。
&&&&&&&&该函数的功能是关闭套接字描述符引用计数,当计数大于0时什么都不干,当计数等于0时触发TCP/IP的,即主动关闭方发送FIN。
&&&&& & 比如:在多进程服务器中,父子进程共享套接字描述符,其引用计数为父进程数+子进程数的和,当父进程或其中某个子进程调用close函数时,描述符计数减一,当所有进程都调用close函数后,引用计数减到0,触发TCP/IP四次挥手过程。
&&&&& & 如果在调用close以前,TCP协议栈的发送队列中有已排队等候发送的数据,则协议栈尝试将数据发送出去,发送完毕后根据套接字描述引用计数来决定是否关闭连接。
&&&&& & 如果在调用close以后,且套接字描述符引用计数为0,则在其上调用write或者read函数则会产生错误码为9即EBADF的错误。
&&&&& & 需要注意的是:调用close函数时,TCP协议栈对发送队列中已排队等候发送数据的处理流程受SO_LINGER选项的影响,该选项关联的数据结构如下:
&&&&& & struct linger{
&&&&&&&&& & int l_& & //0=off,nonzero=on
&&&&&&&&& & int l_& & //linger time
&&&&&&&&};
&&&&& & l_onoff是选项开关,如果是0则关闭选项并且忽略参数l_linger,如果是非零则打开选项,默认是0;l_linger是延迟关闭连接时间,只有l_onoff打开时即为非零时,该参数的值才有效。这几个参数与close时TCP协议栈对待发数据的处理流程如下表:
表1 待发数据处理流程
保持直至发送完成
接管套接字并保证将数据发送至对端
直接发送RST,自身立即复位,不用经过2MSL状态,对端收到复位错误码
阻塞直到l_linger时间超时或数据发送完成(套接字必须设置为阻塞)
在超时时间段内保持尝试发送,若超时则立即放弃
超时则同第二种情况,若发送完成则皆大欢喜
二、shutdown
&&&&& & shutdown函数原型如下:
&&&&& & int shutdown(int sockfd, int howto);
&&&&& & 参数sockfd为套接字描述符,howto取值如下:
&&&&& & (1)SHUT_RD:值为0,关闭连接的读功能。
&&&&& & (2)SHUT_WR:值为1,关闭连接的写功能。
&&&&& & (3)SHUT_RDWR:值为2,先关闭连接的读功能,再关闭连接的写功能。
&&&&& & 成功返回0,错误返回-1,错误码errno:EBADF表示一个非有效描述符;ENOTCONN表示在该描述符上未连接;ENOTSOCK表示是一个文件描述符而非套接字描述符。
&&&&& & shutdown提供了将四次挥手的过程拆分开的可能,需要注意的是,如果调用shutdown时填参数SHUT_WR或者SHUT_RDWR,然后调用write函数则会引发EPIPE/SIGPIPE,因为shutdown以这两个为参数时会发送FIN。
1、是否触发四次挥手
close:只是减少套接字描述符的计数,如果计数为0,则触发四次挥手。
shutdown:拆分四次挥手过程,在设置howto参数为SHUT_WR或者SHUT_RDWR时,会立即发送FIN。
2、多进程共享描述符
close:只要描述符计数不为0,没有调用过该函数的进程仍然可以正常收发数据。
shutdown:无论描述符计数是多少,只要任一进程调用该函数都会破坏所有进程的连接,任一进程在该描述符上读取数据都会收到EOF结束符,写数据时会收到SIGPIPE信号。
阅读(83) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。

我要回帖

更多关于 closesocket 的文章

 

随机推荐