用Socket实现网络编程首先要创建一个Socket对象,Socket类位于System.Net.Socket命名空间,需要先行导入。创建Socket对象需要以下三个参数,这些参数都是枚举类型:
①AddressFamily成员指定Socket用来解析地址的寻址方案,例如:InternetWork指示当Socket使用一个IP版本4地址连接;
②SocketType定义一个要打开的Socket类型;
③Socket类使用ProtocolType枚举向Windows Sockets API通知所请求的协议。
如下代码为服务端创建Socket的代码:
- public partial class FrmService : Form //服务端窗体
- {
- Socket listenSocket = null; //服务器端负责监听的套接字
- Thread connThread = null; //负责监听客户端连接请求的线程
- public FrmService()
- {
- InitializeComponent();
- TextBox.CheckForIllegalCrossThreadCalls = false; //关闭对文本框的跨线程操作检查
- }
- private void btnBeginListen_Click(object sender, EventArgs e)
- {
- //创建服务器端负责监听的套接字,参数(使用IP4寻址协议,使用流式连接,使用TCP协议传输数据)
- listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- //用文本框中的IP地址创建一个IP地址对象IPAddress
- IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
- //创建一个包含IP地址和端口的网络节点对象
- IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
- //把网络节点对象绑定到负责监听的Socket上
- listenSocket.Bind(endpoint);
- //设置监听队列的长度,也就是当前可以同时监听的请求次数
- listenSocket.Listen(10);
- //创建负责监听的线程对象
- connThread = new Thread(WatchConnection);
- //把该线程设置为后台线程
- connThread.IsBackground = true;
- //开启线程
- connThread.Start();
- txtShow.Text = "服务端启动监听成功!";
- }
- /// <summary>
- /// 监听客户端连接事件
- /// </summary>
- private void WatchConnection()
- {
- while (true) //使用一个死循环持续不断的监听新的客户端的连接请求
- {
- //开始监听客户端的连接请求
- Socket connSocket = listenSocket.Accept();
- ShowMsg("客户端连接成功!");
- }
- }
- private void ShowMsg(string message)
- {
- txtShow.Text = message + "\r\n";
- }
- }
服务端负责监听的Socket在使用Accept()方法监听到客户端的连接请求之后,会马上返回一个新的Socket来用于和这个客户端进行通讯。而又由于客户端的数量不确定,因此这里需要一个集合来专门存储Accept()方法返回的与客户端进行通讯的Socket。这样才能让该服务端同时连接上多个客户端。
经过改善后的代码如下:
- public partial class FrmService : Form //服务端窗体
- {
- Socket listenSocket = null; //服务器端负责监听的套接字
- Thread connThread = null; //负责监听连接的线程
- Dictionary<string, Thread> recThreads = new Dictionary<string, Thread>(); //专门负责接收消息的线程
- //Socket connSocket = null; //服务端负责与客户端通讯的Socket
- //专门用于存储//服务端负责与客户端通讯的Socket的集合
- Dictionary<string, Socket> connSockets = new Dictionary<string, Socket>();
- IPEndPoint endpoint = null; //服务端的IP端口
- public FrmService()
- {
- InitializeComponent();
- TextBox.CheckForIllegalCrossThreadCalls = false; //关闭对文本框的跨线程操作检查
- }
- private void btnBeginListen_Click(object sender, EventArgs e)
- {
- //创建服务器端负责监听的套接字,参数(使用IP4寻址协议,使用流式连接,使用TCP协议传输数据)
- listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- //用文本框中的IP地址创建一个IP地址对象IPAddress
- IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
- //创建一个包含IP地址和端口的网络节点对象
- endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
- //把网络节点对象绑定到负责监听的Socket上
- listenSocket.Bind(endpoint);
- //设置监听队列的长度,也就是当前可以同时监听的请求次数
- listenSocket.Listen(10);
- //创建负责监听的线程对象
- connThread = new Thread(WatchConnection);
- //把该线程设置为后台线程
- connThread.IsBackground = true;
- //开启线程
- connThread.Start();
- ShowMsg("服务端启动监听成功!");
- }
- /// <summary>
- /// 监听客户端连接事件
- /// </summary>
- private void WatchConnection()
- {
- while (true) //使用一个死循环持续不断的监听新的客户端的连接请求
- {
- //开始监听客户端的连接请求
- Socket connSocket = listenSocket.Accept();
- //向ListBox中添加一个IP端口字符串,作为访问该客户端的唯一标志
- lbUniqueSign.Items.Add(connSocket.RemoteEndPoint.ToString());
- //将与客户端通讯的Socket添加到集合中
- connSockets.Add(connSocket.RemoteEndPoint.ToString(), connSocket);
- Thread thread = new Thread(ReciveMessage);
- thread.IsBackground = true;
- //以IP端口字符串为Key值,把接收消息的线程添加到recThread集合中。
- recThreads.Add(connSocket.RemoteEndPoint.ToString(), thread);
- thread.Start(connSocket); //传入参数,这个参数是当前负责与这个客户端进行通讯的Socket
- ShowMsg("客户端连接成功!" + connSocket.RemoteEndPoint.ToString());
- }
- }
- private void ShowMsg(string message)
- {
- txtShow.AppendText(message + "\r\n");
- }
- /// <summary>
- /// 发送消息按钮
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void btnSendMsg_Click(object sender, EventArgs e)
- {
- //把发送的消息转换为字节数组
- byte[] arrSendMsg = Encoding.UTF8.GetBytes(txtMessage.Text.Trim());
- //按照选定的IP端口,把消息发送到该客户端上
- connSockets[lbUniqueSign.SelectedItem.ToString()].Send(arrSendMsg);
- //显示消息
- ShowMsg(endpoint.ToString() + "发送消息:");
- ShowMsg("\t"+txtMessage.Text.Trim());
- }
- /// <summary>
- /// 循环接收客户端发送过来的数据
- /// </summary>
- private void ReciveMessage(object socketParam) //接收消息的方法需要一个object类型的参数
- {
- Socket socketClient = socketParam as Socket; //把object类型转换为Socket类型
- while (true)
- {
- //声明一个2M空间的字节数组
- byte[] arrRecMsg = new byte[1024 * 1024 * 2];
- //把接收到的字节存入字节数组中,并获取接收到的字节数
- int length = socketClient.Receive(arrRecMsg);
- //按照接收到的实际字节数获取发送过来的消息
- ShowMsg(socketClient.RemoteEndPoint.ToString() + ":");
- ShowMsg("\t" + Encoding.UTF8.GetString(arrRecMsg, 0, length));
- }
- }
- }
以上代码在改善之后,又添加了一个发送消息方法。发送消息需要调用Socket的Send()方法,它需要一个byte类型的数组参数。我们需要先把要发送的消息转换为byte类型的数组,使用Encoding.UTF8.GetBytes()方法,传入消息参数即可,然后把这个数组传入Send()方法中。上面代码还实现了接收客户端信息的功能,我们把接收消息也放在一个单独的后台线程中。(具体原因在下面)
我们需要从客户端去连接服务端,因此在客户端,我们需要创建一个专门连接服务端的Socket,并传入服务端的IP端口。代码如下:
- public partial class FrmClient : Form //客户端窗体
- {
- private Thread recThread = null; //负责持续获取服务端发来的消息
- private Socket socketClient = null; //创建客户端负责连接的Socket对象
- public FrmClient()
- {
- InitializeComponent();
- TextBox.CheckForIllegalCrossThreadCalls = false;
- }
- private void btnConnectService_Click(object sender, EventArgs e)
- {
- //创建一个IPAddress对象
- IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
- //创建一个包含IP地址和端口的网络节点IPEndPoint对象
- IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
- //创建Socket对象
- socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- //传入网络节点,连接服务端
- socketClient.Connect(endpoint);
- //创建获取消息的后台线程对象
- recThread = new Thread(ReciveMessage);
- recThread.IsBackground = true;
- //开启线程
- recThread.Start();
- }
- /// <summary>
- /// 循环接收服务端发送过来的数据
- /// </summary>
- private void ReciveMessage()
- {
- while (true)
- {
- //声明一个2M空间的字节数组
- byte[] arrRecMsg = new byte[1024 * 1024 * 2];
- //把接收到的字节存入字节数组中,并获取接收到的字节数
- int length = socketClient.Receive(arrRecMsg);
- //按照接收到的实际字节数获取发送过来的消息
- ShowMsg(socketClient.RemoteEndPoint.ToString() + ":");
- ShowMsg("\t" + Encoding.UTF8.GetString(arrRecMsg, 0, length));
- }
- }
- private void ShowMsg(string message)
- {
- txtShow.AppendText(message + "\r\n");
- }
- /// <summary>
- /// 发送消息按钮
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void btnSendMsg_Click(object sender, EventArgs e)
- {
- byte[] arrSendMsg = Encoding.UTF8.GetBytes(txtMessage.Text.Trim());
- socketClient.Send(arrSendMsg);
- ShowMsg("客户端" + "发送消息:");
- ShowMsg("\t"+txtMessage.Text.Trim());
- }
- }
同时启动服务端和客户端两个程序(先启动其中一个项目,然后在解决方案管理器的另外一个项目名上单击右键,在弹出的快捷菜单中选择“调试”里面的“启动新实例”项并单击),运行结果如下图:
博文地址:http://blog.csdn.net/u011416044/article/details/12004819