C#网络编程(同步传输字符串)

本文详细介绍了使用C#进行网络编程,包括服务端客户端通信的同步传输字符串过程。从服务端接收客户端发送的字符串,然后转换为大写回发,客户端接收并打印。通过示例代码,展示了TcpClient和TcpListener的使用,以及在不同编码方式下字符大小的差异。
摘要由CSDN通过智能技术生成


服务端客户端通信

在与服务端的连接建立以后,我们就可以通过此连接来发送和接收数据。端口与端口之间以流(Stream)的形式传输数据,因为几乎任何对象都可以保存到流中,所以实际上可以在客户端与服务端之间传输任何类型的数据。对客户端来说,往流中写入数据,即为向服务器传送数据;从流中读取数据,即为从服务端接收数据。对服务端来说,往流中写入数据,即为向客户端发送数据;从流中读取数据,即为从客户端接收数据。

同步传输字符串

我们现在考虑这样一个任务:客户端打印一串字符串,然后发往服务端,服务端先输出它,然后将它改为大写,再回发到客户端,客户端接收到以后,最后再次打印一遍它。我们将它分为两部分:1、客户端发送,服务端接收并输出;2、服务端回发,客户端接收并输出。

1.客户端发送,服务端接收并输出

1.1服务端程序

我们可以在TcpClient上调用GetStream()方法来获得连接到远程计算机的流。注意这里我用了远程这个词,当在客户端调用时,它得到连接服务端的流;当在服务端调用时,它获得连接客户端的流。接下来我们来看一下代码,我们先看服务端(注意这里没有使用do/while循环):

class Server {
    static void Main(string[] args) {
        const int BufferSize = 8192;    // 缓存大小,8192字节
                    
        Console.WriteLine("Server is running ... ");
        IPAddress ip = new IPAddress(new byte[] { 127, 0, 0, 1 });
        TcpListener listener = new TcpListener(ip, 8500);

        listener.Start();           // 开始侦听
        Console.WriteLine("Start Listening ...");
        
        // 获取一个连接,中断方法
        TcpClient remoteClient = listener.AcceptTcpClient();
        // 打印连接到的客户端信息
        Console.WriteLine("Client Connected!{0} <-- {1}",
            remoteClient.Client.LocalEndPoint, remoteClient.Client.RemoteEndPoint);

        // 获得流,并写入buffer中
        NetworkStream streamToClient = remoteClient.GetStream();
        byte[] buffer = new byte[BufferSize];
        int bytesRead = streamToClient.Read(buffer, 0, BufferSize);
        Console.WriteLine("Reading data, {0} bytes ...", bytesRead);

        // 获得请求的字符串
        string msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);
        Console.WriteLine("Received: {0}", msg);

        // 按Q退出
    }
}

这段程序的上半部分已经很熟悉了,我就不再解释。remoteClient.GetStream()方法获取到了连接至客户端的流,然后从流中读出数据并保存在了buffer缓存中,随后使用Encoding.Unicode.GetString()方法,从缓存中获取到了实际的字符串。最后将字符串打印在了控制台上。这段代码有个地方需要注意:在能够读取的字符串的总字节数大于BufferSize的时候会出现字符串截断现象,因为缓存中的数目总是有限的,而对于大对象,比如说图片或者其它文件来说,则必须采用“分次读取然后转存”这种方式,比如这样:

// 获取字符串
byte[] buffer = new byte[BufferSize];
int bytesRead;          // 读取的字节数
MemoryStream msStream = new MemoryStream();
do {
    bytesRead = streamToClient.Read(buffer, 0, BufferSize);
    msStream.Write(buffer, 0, bytesRead);
while (bytesRead > 0);

buffer = msStream.GetBuffer();
string msg = Encoding.Unicode.GetString(buffer);

这里我没有使用这种方法,一个是因为不想关注在太多的细节上面,一个是因为对于字符串来说,8192字节已经很多了,我们通常不会传递这么多的文本。当使用Unicode编码时,8192字节可以保存4096个汉字和英文字符。使用不同的编码方式,占用的字节数有很大的差异,在本文最后面,有一段小程序,可以用来测试Unicode、UTF8、ASCII三种常用编码方式对字符串编码时,占用的字节数大小。

现在对客户端不做任何修改,然后运行先运行服务端,再运行客户端。结果我们会发现这样一件事:服务端再打印完“Client Connected!127.0.0.1:8500 <-- 127.0.0.1:xxxxx”之后,再次被阻塞了,而没有输出“Reading data, {0} bytes ...”。可见,与AcceptTcpClient()方法类似,这个Read()方法也是同步的,只有当客户端发送数据的时候,服务端才会读取数据、运行此方法,否则它便会一直等待。

1.2 客户端程序

接下来我们编写客户端向服务器发送字符串的代码,与服务端类似,它先获取连接服务器端的流,将字符串保存到buffer缓存中,再将缓存写入流,写入流这一过程,相当于将消息发往服务端。

class Client {
    static void Main(string[] args) {
        Console.WriteLine("Client Running ...");
        TcpClient client;

        try {
            client = new TcpClient();
            client.Connect("localhost", 8500);      // 与服务器连接
        } catch (

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值