socket编程笔记
服务端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | class Client { TcpClient clientSocket; StreamWriter writer; public Client(TcpClient client) { clientSocket = client; NetworkStream stream = clientSocket.GetStream(); writer = new StreamWriter(stream,Encoding.ASCII); } public void write( string str) { //flush也很重要 如果你想发出去过后客户端立即就收到请使用这个 要不他会把数据放到缓冲区里 //客户端也就一直在read那里等待 writer.WriteLine(str); writer.Flush(); } public void close() { //是否调用了close 然后客户端等待一段时间再read就会收不到数据呢 或者提示服务端已断开异常呢 //否 只有马上运行完后此socket不进行close 直接关闭程序。这时客户端read操作才会报连接断开异常 //在这之前客户端会持续的读到服务端发过去的数据 //注意:只要服务端先发送数据然后通过正常手续依次关闭socket、监听 然后程序退出 //那么客户端也不会有问题 //看似客户端还没来得及收数据 //实际上write方法运行完毕这个数据就已经写到客户端缓冲区了(这种小数据实际上一瞬间就传过去了) //tcp就是要保证数据已经正确到达目标机后收到一个确认后才会继续发后面的数据的 //tcp正是通过这种机制维护了数据的完整性 //服务端正常close 那么客户端唯一判断的方式就是read方法返回0 说明连接的另一端已经退出 //只要还有连接 那么客户端调用同步read方法那么不读到数据线程是会被阻塞的就一直卡在那里 //如果写了数据不立即Flush他也会暂时收不到数据也会卡在那里 //如果服务端非正常关闭 则客户端read的时候产生连接断开异常 //基于以上所以程序两端要"商量"着一起退出程序时通常是给对方发消息 收到消息后进行close writer.Close(); clientSocket.Close(); } } class Program { static void Main( string [] args) { TcpListener server = new TcpListener(6000); server.Start(); //while (true) //{ Client c = new Client(server.AcceptTcpClient()); Console.WriteLine( "新的连接" ); //Thread.Sleep(2000); for ( int i = 0; i < 3; i++) { c.write( "hello,welcome ^_^" + i.ToString()); //Thread.Sleep(1000); } Thread.Sleep(5000); c.write( "finally" ); Console.WriteLine( "发送完成" ); Thread.Sleep(10000); c.close(); //Thread.Sleep(100000); //} server.Stop(); } } |
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | class Program { static void Main( string [] args) { TcpClient client = new TcpClient(); client.Connect(IPAddress.Parse( @"127.0.0.1" ), 6000); Console.WriteLine( "连上了" ); StreamReader reader = new StreamReader(client.GetStream()); //Thread.Sleep(6000); while ( true ) { try { byte [] data = new byte [1024]; //if (client.Available > 0) //{ //read方法使用 //第三个参数不一定是client.Available 因为别人到底发了多少数据过来是未知的 //自己想对多少个字节解码就读多少字节就是了 //可能想到Read方法返回的读取数是0 tcp是有连接的有状态的 所以每次Read是必定能读到东西的 //如果调用同步Read方法没有读到对方发过来的东西 他会挂起直到读到数据为止 //如果调用后立即返回0说明连接已经断开了 //Thread.Sleep(2000); int reds = reader.BaseStream.Read(data, 0, data.Length); if (reds == 0) break ; if (Encoding.ASCII.GetString(data).IndexOf( "finally" ) != -1) { Console.WriteLine(Encoding.ASCII.GetString(data, 0, reds)); break ; } if (reds < data.Length) Console.WriteLine(Encoding.ASCII.GetString(data, 0, reds)); else Console.WriteLine(Encoding.ASCII.GetString(data)); //当缓冲区内没有数据时立即就中断读取是不妥的 //有可能网络延迟数据还没有发过来 //} //else // break; } catch (Exception ex) { Console.WriteLine( "服务端已断开:" + ex.Message); break ; } } Console.WriteLine( "over" ); client.Close(); Console.ReadKey(); } } |
标签:
socket c#
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期