c#中的socket中的time_wait状态处理方法

端口的状态说明:

TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源。在众多TCP状态中,最值得注意的状态有两个:CLOSE_WAIT和TIME_WAIT。 
 
1、LISTENING状态
  FTP服务启动后首先处于侦听(LISTENING)状态。

2、ESTABLISHED状态
  ESTABLISHED的意思是建立连接。表示两台机器正在通信。

3、CLOSE_WAIT

    对方主动关闭连接或者网络异常导致连接中断,这时我方的状态会变成CLOSE_WAIT 此时我方要调用close()来使得连接正确关闭

4、TIME_WAIT

    我方主动调用close()断开连接,收到对方确认后状态变为TIME_WAIT。TCP协议规定TIME_WAIT状态会一直持续2MSL(即两倍的分段最大生存期),以此来确保旧的连接状态不会对新连接产生影响。处于TIME_WAIT状态的连接占用的资源不会被内核释放,所以作为服务器,在可能的情况下,尽量不要主动断开连接,以减少TIME_WAIT状态造成的资源浪费。

 

客户端在 设置了

      LingerOption linerOption = new LingerOption(false, 0);

      tcpServer.LingerState = linerOption;

发现还是有time_wait状态

 

在MSDN中 有这样一句话:

           

   Connected 属性获取截止到最后一次 I/O 操作时的 Client 套接字的连接状态。如果该属性返回 false,则表明 Client 要么从未连接,要么已断开连接。

由于 Connected 属性仅反映截止到最近的操作时的连接状态,因此您应该尝试发送或接收一则消息以确定当前状态。当该消息发送失败后,此属性将不再返回 true。注意此行为是设计使然。您无法可靠地测试连接状态,因为在测试与发送/接收之间,连接可能已丢失。您的代码应该假定套接字已连接,并妥善处理失败的传输。

 

因此在客户端发送完成数据后发送完成主体数据之后再通过有限次数循环来向服务端发送断开连接的请求,服务端 在收到后主动先主动关闭连接,之后本端会在某次发送数据过程中抛出异常,通过这个异常 本端再关闭连接,这样可以完全清除tcp中的time_wait状态。否则按照正常流程关闭连接。客户端代码如下:

                 

                   int waitTime = 3;//重试时长
                    totalBytesToSend = AddSendDataLength(isConnected);//结束连接数据
                    while (waitTime > 0)
                    {
                        if (tcpServer.Connected)
                        {
                            //重试三次数据(请求服务端结束连接的数据)的发送,直到(检测到客户端已经断开连接为止,或者检测超出最大检测次数。)
                            sendPoint = 0;//缓存起始发送点
                            curSend = 0;//上一次发送的长度
                           
                            while (sendPoint < totalBytesToSend.Length)
                            {
                                curSend = tcpServer.Client.Send(totalBytesToSend, sendPoint, totalBytesToSend.Length - sendPoint, SocketFlags.None);
                                sendPoint += curSend;
                            }

                            System.Threading.Thread.Sleep(500);//线程阻塞一定时间
                        }
                        else {
                            break;
                        }

                        waitTime--;
                    }
                    tcpServer.Client.Shutdown(SocketShutdown.Both);
                    tcpServer.Client.Close();

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用 C# 和 Java 实现 Socket 传输 Protobuf 字节流的过程可以分为以下几个步骤: 1. 定义 Protobuf 消息结构 首先,需要使用 Protocol Buffers 定义消息结构。假设我们要传输的消息结构如下: ``` message Person { string name = 1; int32 age = 2; repeated string phone_number = 3; } ``` 2. 生成代码 使用 protobuf 编译器生成 C# 和 Java 的代码,方法如下: ``` protoc --csharp_out=. person.proto protoc --java_out=. person.proto ``` 3. C# 实现 Socket 发送 首先,在 C# 创建一个 `Person` 对象,并将其序列化为字节数组,然后将其发送到 Java 服务器: ```csharp using System; using System.Net.Sockets; using Google.Protobuf; class Program { static void Main(string[] args) { // 创建 Person 对象 var person = new Person { Name = "张三", Age = 18, PhoneNumber = { "123456789", "987654321" } }; // 将 Person 对象序列化为字节数组 byte[] data = person.ToByteArray(); // 创建 Socket 连接 var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Connect("127.0.0.1", 8888); // 发送数据 socket.Send(data); // 关闭连接 socket.Shutdown(SocketShutdown.Both); socket.Close(); } } ``` 4. Java 实现 Socket 接收 在 Java ,我们需要创建一个 `ServerSocket`,并监听指定的端口。当有连接请求时,我们可以使用 `Socket` 接收数据,并将其反序列化为 `Person` 对象: ```java import com.example.PersonOuterClass.Person; import com.google.protobuf.InvalidProtocolBufferException; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Main { public static void main(String[] args) throws IOException { // 创建 ServerSocket,监听指定端口 ServerSocket serverSocket = new ServerSocket(8888); while (true) { // 等待连接 Socket socket = serverSocket.accept(); // 读取数据 byte[] buffer = new byte[socket.getInputStream().available()]; socket.getInputStream().read(buffer); try { // 将字节数组反序列化为 Person 对象 Person person = Person.parseFrom(buffer); System.out.println(person); } catch (InvalidProtocolBufferException e) { e.printStackTrace(); } // 关闭连接 socket.shutdownInput(); socket.close(); } } } ``` 这样,就完成了 C# 和 Java 之间通过 Socket 传输 Protobuf 字节流的实例。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值