C#中的socket编程入门实例

来源:互联网 发布:bind javascript 编辑:程序博客网 时间:2024/05/16 00:41

Socket主要是通过TCP或者UDP协议进行多台主机之间的通讯。由于项目中用到,所以今天就结合项目需求对socket编程的C#表示进行一步一步详细的介绍。
TCP的详细过程我就不多介绍了,这个是网络基础,不明白的同学可以看TCP


开启服务端对端口的监听

我们都知道TCP服务端需要对某个端口进行连续监听,客户端才可以发起连接。所以我们先讲讲服务端如何打开端口进行监听。
新建一个控制台应用程序ServerConsole,引用System.NetSystem.Net.Sockets
代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace ServerConsole{    class Program    {        static void Main(string[] args)        {            Console.WriteLine("Server is running...");            IPAddress ip = IPAddress.Parse("127.0.0.1");//获取ip地址            TcpListener listener = new TcpListener(ip, 8500);            listener.Start();//开始监听            Console.WriteLine("Start Listening...");            Console.WriteLine("\n\n 输入 \"Q\"键退出。");            ConsoleKey key;            do            {                key = Console.ReadKey(true).Key;            } while (key != ConsoleKey.Q);        }    }}

运行后,通过cmd netstat –a 可以查看已经开启8500端口监听:
开启端口


客户端与服务器连接

服务端开启端口监听后,接下来就是客户端来发起连接了。
创建一个新的控制台命令程序ClientConsole,代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace ClientConsole{    class Program    {        static void Main(string[] args)        {            Console.WriteLine("Client Running...");            TcpClient client = new TcpClient();            try            {                client.Connect("localhost", 8500);//与服务器连接            }            catch (Exception ex){                Console.WriteLine(ex.Message);                return;            }            //打印连接到的服务器信息            Console.WriteLine("Server Connected! {0}-->{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint);            //按Q退出            Console.WriteLine("\n\n 输入 \"Q\"键退出。");            ConsoleKey key;            do            {                key = Console.ReadKey(true).Key;            } while (key != ConsoleKey.Q);        }    }}

当我们同时运行服务端ServerConsole和客户端ClientConsole后,客户端程序效果:
这里写图片描述

可以看到,客户端开启了55279端口和服务端成功建立连接。客户端使用的端口号是随机选取的,并不需要我们来设置,并且每次运行时,端口都不同。8500端口和客户端建立连接后,仍然处于监听状态,也就是说一个端口可以和多个远程端口进行通信。


服务端和客户端通信

连接已经成功建立了,接下来需要进行的就是通信了。
由于这里只是入门介绍,所以不涉及到文件的传输,我们主要还是介绍字节流的传输过程。

客户端发送,服务端接收

我们先从一条数据开始循序渐进吧。
服务端Server代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace Server{    class Program    {        static void Main(string[] args)        {            const int BufferSize = 8192;//缓存大小,8192字节,可以保存4096个汉字和英文字符            Console.WriteLine("Server is running ...");            IPAddress ip = IPAddress.Parse("127.0.0.1");//获取ip地址            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退出            Console.WriteLine("\n\n 输入 \"Q\"键退出。");            ConsoleKey key;            do            {                key = Console.ReadKey(true).Key;            } while (key != ConsoleKey.Q);        }    }}

可以看到,我们利用服务端监听客户端传入字节流,将其放入缓存并输出。
客户端代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace Client{    class Program    {        static void Main(string[] args)        {            Console.WriteLine("Client Running...");            TcpClient client = new TcpClient();            try            {                client.Connect("localhost", 8500);//与服务器连接            }            catch (Exception ex)            {                Console.WriteLine(ex.Message);                return;            }            //打印连接到的服务器信息            Console.WriteLine("Server Connected! {0}-->{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint);            //定义要传送的信息            string msg = "\"欢迎连接到服务器!\"";            NetworkStream streamToServer = client.GetStream();            //发送信息            byte[] buffer = Encoding.Unicode.GetBytes(msg);//获得缓存            streamToServer.Write(buffer, 0, buffer.Length);//发往服务器            Console.WriteLine("Sent:{0}", msg);            //按Q退出            Console.WriteLine("\n\n 输入 \"Q\"键退出。");            ConsoleKey key;            do            {                key = Console.ReadKey(true).Key;            } while (key != ConsoleKey.Q);        }    }}

这里是NetworkStream 类型就是字节流传输的一个载体。我们将客户端程序中定义好的字符串“欢迎连接到服务器!”传输给服务端。

客户端效果如下:
这里写图片描述

服务端效果如下:
这里写图片描述

可以看到服务端成功接收客户端信息。

客户端发送多条,服务端接收多条

再来看看我们如何一次发送多个信息到服务器。
服务端ServerMany代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace ServerMany{    class Program    {        static void Main(string[] args)        {            const int BufferSize = 8192;//缓存大小,8192字节,可以保存4096个汉字和英文字符            Console.WriteLine("Server is running ...");            IPAddress ip = IPAddress.Parse("127.0.0.1");//获取ip地址            TcpListener listener = new TcpListener(ip, 8500);            listener.Start();//开始监听            Console.WriteLine("Start Listening...");            do            {                //获取一个连接,中断方法                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);            } while (true);            //按Q退出            Console.WriteLine("\n\n 输入 \"Q\"键退出。");            ConsoleKey key;            do            {                key = Console.ReadKey(true).Key;            } while (key != ConsoleKey.Q);        }    }}

我们通过do while循环一直等待客户端传输信息。
客户端ClientMany代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace ClientMany{    class Program    {        static void Main(string[] args)        {            Console.WriteLine("Client Running...");            TcpClient client;            //启动多个服务器            for (int i = 0; i < 5; i++)            {                try                {                    client = new TcpClient();                    client.Connect("localhost", 8500);//与服务器连接                }                catch (Exception ex)                {                    Console.WriteLine(ex.Message);                    return;                }                //打印连接到的服务器信息                Console.WriteLine("Server Connected! {0}-->{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint);                //定义要传送的信息                string msg = "\"欢迎连接到服务器!\"";                NetworkStream streamToServer = client.GetStream();                //发送信息                byte[] buffer = Encoding.Unicode.GetBytes(msg);//获得缓存                streamToServer.Write(buffer, 0, buffer.Length);//发往服务器                Console.WriteLine("Sent:{0}", msg);            }            //按Q退出            Console.WriteLine("\n\n 输入 \"Q\"键退出。");            ConsoleKey key;            do            {                key = Console.ReadKey(true).Key;            } while (key != ConsoleKey.Q);        }    }}

这里我们先通过一个for循环传输多条数据。
客户端效果如下:
这里写图片描述

服务端效果如下:
这里写图片描述

客户端发送自定义信息,服务端接收自定义信息

前面的demo中我们发送的信息都是固定在程序中的。现在我们对其进行改进,使客户端可以发送自定义的信息。
服务端ServerManySelf代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace ServerManySelf{    class Program    {        static void Main(string[] args)        {            const int BufferSize = 8192;//缓存大小,8192字节,可以保存4096个汉字和英文字符            Console.WriteLine("Server is running ...");            IPAddress ip = IPAddress.Parse("127.0.0.1");//获取ip地址            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();            do            {                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);            } while (true);            //按Q退出            Console.WriteLine("\n\n 输入 \"Q\"键退出。");            ConsoleKey key;            do            {                key = Console.ReadKey(true).Key;            } while (key != ConsoleKey.Q);        }    }}

服务端的代码基本没有什么变化,客户端ClientManySelf代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace ClientManySelf{    class Program    {        static void Main(string[] args)        {            Console.WriteLine("Client Running...");            TcpClient client;            //启动多个服务器            for (int i = 0; i < 5; i++)            {                try                {                    client = new TcpClient();                    client.Connect("localhost", 8500);//与服务器连接                }                catch (Exception ex)                {                    Console.WriteLine(ex.Message);                    return;                }                //打印连接到的服务器信息                Console.WriteLine("Server Connected! {0}-->{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint);                NetworkStream streamToServer = client.GetStream();                ConsoleKey key;                Console.WriteLine("Menu:S-Send,X-Exit");                do                {                    key = Console.ReadKey(true).Key;                    if (key == ConsoleKey.S)                    {                        //获取输入的字符串                        Console.Write("输入信息:");                        string msg = Console.ReadLine();                        //发送信息                        byte[] buffer = Encoding.Unicode.GetBytes(msg);//获得缓存                        streamToServer.Write(buffer, 0, buffer.Length);//发往服务器                        Console.WriteLine("Sent:{0}", msg);                    }                } while (key != ConsoleKey.X);            }        }    }}

我们通过交互来完成客户端的输入,从而发送自定义的信息到服务端。
客户端效果:
这里写图片描述

服务端效果:
这里写图片描述

服务端回发信息,客户端接收

TCP是双向通信的,前面一直介绍的是客户端发送信息到服务端,接下来介绍如何从服务端发送信息到客户端。
服务端通过Read方法读信息,所以通过Write方法写信息。
我们想象一个需求,就是服务端将客户端发送过来的字符串变为大写后再传输回客户端。
服务端ServerSend代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace ServerSend{    class Program    {        static void Main(string[] args)        {            const int BufferSize = 8192;//缓存大小,8192字节,可以保存4096个汉字和英文字符            Console.WriteLine("Server is running ...");            IPAddress ip = IPAddress.Parse("127.0.0.1");//获取ip地址            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);            //转换成大写并发送            msg = msg.ToUpper();            buffer = Encoding.Unicode.GetBytes(msg);            lock (streamToClient) {                streamToClient.Write(buffer, 0, buffer.Length);            }            Console.WriteLine("Send:{0}", msg);            //按Q退出            Console.WriteLine("\n\n 输入 \"Q\"键退出。");            ConsoleKey key;            do            {                key = Console.ReadKey(true).Key;            } while (key != ConsoleKey.Q);        }    }}

客户端同意通过Read方法来读,客户端ClientAccept代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace ClientAccept{    class Program    {        static void Main(string[] args)        {             const int BufferSize = 8192;//缓存大小,8192字节,可以保存4096个汉字和英文字符            Console.WriteLine("Client Running...");            TcpClient client;            //启动多个服务器            for (int i = 0; i < 5; i++)            {                try                {                    client = new TcpClient();                    client.Connect("localhost", 8500);//与服务器连接                }                catch (Exception ex)                {                    Console.WriteLine(ex.Message);                    return;                }                //打印连接到的服务器信息                Console.WriteLine("Server Connected! {0}-->{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint);                NetworkStream streamToServer = client.GetStream();                ConsoleKey key;                Console.WriteLine("Menu:S-Send,X-Exit");                do                {                    key = Console.ReadKey(true).Key;                    if (key == ConsoleKey.S)                    {                        //获取输入的字符串                        Console.Write("输入信息:");                        string msg = Console.ReadLine();                        //发送信息                        byte[] buffer = Encoding.Unicode.GetBytes(msg);//获得缓存                        streamToServer.Write(buffer, 0, buffer.Length);//发往服务器                        Console.WriteLine("Sent:{0}", msg);                        //获取信息                        int bytesRead;                        buffer = new byte[BufferSize];                        lock (streamToServer) {                            bytesRead = streamToServer.Read(buffer, 0, BufferSize);                        }                        msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);                        Console.WriteLine("Received:{0}", msg);                    }                } while (key != ConsoleKey.X);            }        }    }}

客户端效果如下:
这里写图片描述

服务端效果如下:
这里写图片描述

服务端指定ID,客户端对数据库进行查询

双向通信也介绍了。最后以一个我在项目中需要用到的功能来收尾。我们通过服务端发送需要查询的ID,然后客户端通过ID对Access数据库进行查询,并将结果返回给服务端。
服务端ServerSQL代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;namespace ServerSQL{    class Program    {        static void Main(string[] args)        {            const int BufferSize = 8192;//缓存大小,8192字节,可以保存4096个汉字和英文字符            Console.WriteLine("Server is running ...");            IPAddress ip = IPAddress.Parse("127.0.0.1");//获取ip地址            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);            //发送信息            ConsoleKey key;            Console.WriteLine("Menu:S-Send,X-Exit");            do            {                key = Console.ReadKey(true).Key;                if (key == ConsoleKey.S)                {                    //获取输入的字符串                    Console.Write("输入信息:");                    msg = Console.ReadLine();                    //发送信息                    buffer = Encoding.Unicode.GetBytes(msg);//获得缓存                    streamToClient.Write(buffer, 0, buffer.Length);//发往服务器                    Console.WriteLine("Sent:{0}", msg);                    //获取流,并写入buffer中                    streamToClient = remoteClient.GetStream();                    buffer = new byte[BufferSize];                    bytesRead = streamToClient.Read(buffer, 0, BufferSize);//一直等待客户端传信息                    Console.WriteLine("Reading data,{0} bytes...", bytesRead);                    //获得请求的字符串                    msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);                    Console.WriteLine("Received:{0}", msg);                }            } while (key != ConsoleKey.X);            //按Q退出            Console.WriteLine("\n\n 输入 \"Q\"键退出。");            do            {                key = Console.ReadKey(true).Key;            } while (key != ConsoleKey.Q);        }    }}

客户端ClientSQL代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;//数据库引用using System.Data;using System.Data.OleDb;//Socket引用using System.Net;using System.Net.Sockets;namespace ClientSQL{    class Program    {        /// <summary>        /// 数据库连接        /// </summary>        /// <returns>数据库连接对象</returns>        public static OleDbConnection getConn()         {            string connstr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=G:\\users\\brizer\\documents\\visual studio 2010\\Projects\\socket\\test.mdb";            OleDbConnection tempconn = new OleDbConnection(connstr);            return tempconn;        }        /// <summary>        /// 获取需要的信息        /// </summary>        /// <param name="id">通过参数查询</param>        /// <returns>得到查询结果的字节流</returns>        public static string getValueFromId(string id)        {            string tempValue = "";//定义返回值            try            {                OleDbConnection conn = getConn();//得到连接对象                string strCom = "Select * from testTable where id =" + id;                OleDbCommand myCommand = new OleDbCommand(strCom, conn);                conn.Open();                OleDbDataReader reader;                reader = myCommand.ExecuteReader();//执行命令并得到相应的DataReader                //下面将得到的值赋给tempValue对象                if (reader.Read())                {                    tempValue = "ID:" + reader["id"].ToString();                    tempValue += "温度:" + reader["温度"].ToString();                    tempValue += "长度:" + reader["长度"].ToString();                }                else                {                    tempValue = "没有该记录";                }            }            catch (Exception e)            {            }            return tempValue;        }        /// <summary>        /// 将字节流传给服务端        /// </summary>        /// <param name="value">需要传送的内容</param>        public static void sendToServer(string value)        {            const int BufferSize = 8192;//缓存大小,8192字节,可以保存4096个汉字和英文字符             Console.WriteLine("Client Running...");            TcpClient client = new TcpClient();            try            {                client.Connect("localhost", 8500);//与服务器连接            }            catch (Exception ex)            {                Console.WriteLine(ex.Message);                return;            }            //打印连接到的服务器信息            Console.WriteLine("Server Connected! {0}-->{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint);            //定义要传送的信息            string msg = value;            NetworkStream streamToServer = client.GetStream();            //发送信息            byte[] buffer = Encoding.Unicode.GetBytes(msg);//获得缓存            streamToServer.Write(buffer, 0, buffer.Length);//发往服务器            Console.WriteLine("Sent:{0}", msg);            //接收信息            do            {                buffer = new byte[BufferSize];                int bytesRead = streamToServer.Read(buffer, 0, BufferSize);//一直等待客户端传信息                Console.WriteLine("Reading data,{0} bytes...", bytesRead);                //获得请求的字符串                msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);                Console.WriteLine("Received:{0}", msg);                string result = getValueFromId(msg);                Console.WriteLine("结果:{0}", result);                //将结果发送给服务端                msg = result;                byte[] bufferWrite = Encoding.Unicode.GetBytes(result);                streamToServer.Write(bufferWrite, 0, bufferWrite.Length);//发往服务器            } while (true);            //按Q退出            Console.WriteLine("\n\n 输入 \"Q\"键退出。");            ConsoleKey key;            do            {                key = Console.ReadKey(true).Key;            } while (key != ConsoleKey.Q);        }        static void Main(string[] args)        {            //获取需要的数据信息            string value;            value = getValueFromId("2");            //Console.WriteLine(value);            //Console.ReadKey();            //通过TCP传到服务端            sendToServer(value);        }    }}

Access数据库test中内容如下:
这里写图片描述

服务端效果如下:
这里写图片描述

客户端效果如下:
这里写图片描述

成功将客户端指定数据传输至服务端。
全部实例下载地址

2 0
原创粉丝点击