通过本文主要向大家介绍了c#ftp客户端源代码,c#socket客户端,c#获取客户端ip地址,c#客户端连接服务器,c#客户端和服务端等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
本文所述为基于C#实现的多人聊天程序服务端与客户端完整代码。本实例省略了结构定义部分,服务端主要是逻辑处理部分代码,因此使用时需要完善一些窗体按钮之类的。
先看服务端代码如下:
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Net; using System.Net.Sockets; using System.Threading; namespace 多人聊天程序Server端 { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { Application.Run(new Form1()); } // 启动服务按钮 private void button2_Click(object sender, System.EventArgs e) { try { // 必须填写端口 if(txtPort.Text == "") { MessageBox.Show("请先填写服务端口号!", "提示"); return; } Int32 port = Int32.Parse(txtPort.Text); // 获得端口号 // 创建侦听的Socket mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint localEP = new IPEndPoint(IPAddress.Any, port); // 将 Socket 绑定到本地的终结点上 mainSocket.Bind(localEP); // 开始侦听,最大的连接数是 5 mainSocket.Listen(5); // 开始一个异步操作接受客户的连接请求 mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null); // 启动服务按钮不可用,停止服务按钮可用 UpdateControls(true); } catch(SocketException se) { MessageBox.Show(se.Message, "提示"); } } // 更新“启动服务按钮”和“停止服务”按钮的状态:是否可用; // 注意:两个按钮的状态是互斥的 private void UpdateControls(bool onServe) { button2.Enabled = !onServe; button3.Enabled = onServe; if(onServe) { status.Text = "已启动服务"; } else { status.Text = "未启动服务"; } } // 回调函数,当客户连接上时,将会被调用 public void OnClientConnect(IAsyncResult asyn) { try { // 调用EndAccept完成BeginAccept异步调用,返回一个新的Socket处理与客户的通信 Socket workerSocket = mainSocket.EndAccept(asyn); // 增加客户数目 Interlocked.Increment(ref clientNum); // 将 workerSocket Socket加入到 ArrayList 中 workerSocketList.Add(workerSocket); // 发送欢迎信息给连接上服务器的客户 string msg = "欢迎客户 " + clientNum + " 登录服务器\n"; SendWelcomeToClient(msg, clientNum); // 在线客户数目改变,必须更新客户列表 UpdateClientListControl(); // 连接上的客户接收数据 WaitForData(workerSocket, clientNum); // 主 Socket 返回,继续等待其它的连接请求 mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null); } catch(ObjectDisposedException) { System.Diagnostics.Debugger.Log(0,"1","\n OnClientConnection: Socket已经关闭!\n"); } catch(SocketException se) { MessageBox.Show(se.Message, "提示"); } } // 发送欢迎信息给客户 void SendWelcomeToClient(string msg, int clientNumber) { // 用UTF8格式来将string信息转化成byte数组形式 byte[] byData = System.Text.Encoding.UTF8.GetBytes(msg); // 获得客户clientNumber对应的Socket Socket workerSocket = (Socket)workerSocketList[clientNumber - 1]; // 将数据发给客户 workerSocket.Send(byData); } // 该类保存当前的socket,它的客户号还有发送给服务器的数据 public class SocketPacket { public System.Net.Sockets.Socket currentSocket; // 当前的Socket public int clientNumber; // 客户号 public byte[] dataBuffer = new byte[1024]; // 发给服务器的数据 // 构造函数 public SocketPacket(System.Net.Sockets.Socket socket, int clientNumber) { currentSocket = socket; this.clientNumber = clientNumber; } } // 开始等待客户发送数据 public void WaitForData(System.Net.Sockets.Socket socket, int clientNumber) { try { if(pfnWorkerCallBack == null) { // 当连接上的客户有写的操作的时候,调用回调函数 pfnWorkerCallBack = new AsyncCallback(OnDataReceived); } SocketPacket socketPacket = new SocketPacket(socket, clientNumber); socket.BeginReceive(socketPacket.dataBuffer, 0, socketPacket.dataBuffer.Length, SocketFlags.None, pfnWorkerCallBack, socketPacket); } catch(SocketException se) { MessageBox.Show (se.Message, "提示"); } } // 当客户写数据时,调用以下方法 public void OnDataReceived(IAsyncResult asyn) { SocketPacket socketData = (SocketPacket)asyn.AsyncState ; try { // EndReceive完成BeginReceive异步调用,返回客户写入流的字节数 int iRx = socketData.currentSocket.EndReceive(asyn); // 加 1 是因为字符串以 '\0' 作为结束标志符 char[] chars = new char[iRx + 1]; // 对客户发来的信息进行UTF8解码,存入chars字符数组中 System.Text.Decoder decoder = System.Text.Encoding.UTF8.GetDecoder(); int charLen = decoder.GetChars(socketData.dataBuffer, 0, iRx, chars, 0); System.String szData = new System.String(chars); string msg = "客户 " + socketData.clientNumber + " 发的信息:" + szData; // 将客户发的数据加入到信息列表中 AppendToRichEditControl(msg); // 等待数据 WaitForData(socketData.currentSocket, socketData.clientNumber); } catch (ObjectDisposedException ) { System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket已经关闭!\n"); } catch(SocketException se) { if(se.ErrorCode == 10054) { // 将客户断开连接的信息写入信息列表中 string msg = "客户 " + socketData.clientNumber + " 已断开了连接!" + "\n"; AppendToRichEditControl(msg); // 移走已关闭的socket workerSocketList[socketData.clientNumber - 1] = null; // 更新客户列表 UpdateClientListControl(); } else { MessageBox.Show (se.Message, "提示"); } } } // 更新信息列表,该方法可由主线程或其他工作线程所调用 private void AppendToRichEditControl(string msg) { // 测试看是哪个线程调用了该方法 if (InvokeRequired) { // We cannot update the GUI on this thread. // All GUI controls are to be updated by the main (GUI) thread. // Hence we will use the invoke method on the control which will // be called when the Main thread is free // Do UI update on UI thread object[] pList = {msg}; txtRecvMsg.BeginInvoke(new UpdateRichEditCallback(OnUpdateRichEdit), pList); } else { // 创建该控件的主线程直接更新信息列表 OnUpdateRichEdit(msg); } } // 添加信息到 txtRecvMsg 中 private void OnUpdateRichEdit(string msg) { // txtRecvMsg.AppendText(msg); txtRecvMsg.Text = txtRecvMsg.Text + msg; } // 更新客户列表 private void UpdateClientListControl() { if (InvokeRequired) // Is this called from a thread other than the one created // the control { clientList.BeginInvoke(new UpdateClientListCallback(UpdateClientList), null); } else { // 创建该控件的主线程直接更新信息列表 UpdateClientList(); } } // 更新客户列表 void UpdateClientList() { clientList.Items.Clear(); // 清空客户列表 for(int i = 0; i < workerSocketList.Count; i++) { // 加1,是因为数组从下标0开始,而我们的客户标号是从1开始 string clientKey = Convert.ToString(i + 1); Socket workerSocket = (Socket)workerSocketList[i]; if(workerSocket != null) { // 将连接着服务器的客户添加到客户列表中 if(workerSocket.Connected) { clientList.Items.Add(clientKey); } } } } // 停止服务按钮 private void button3_Click(object sender, System.EventArgs e) { CloseSockets(); UpdateControls(false); // 更新客户列表 UpdateClientListControl(); } // 发送信息按钮 private void button1_Click(object sender, System.EventArgs e) { // 如果在线客户列表不为空,则允许发送信息 if (clientList.Items.Count != 0 ) { try { string msg = txtSendMsg.Text; msg = "服务器信息: " + msg + "\n"; byte[] byData = System.Text.Encoding.UTF8.GetBytes(msg); Socket workerSocket = null; for(int i = 0; i < workerSocketList.Count; i++) { workerSocket = (Socket)workerSocketList[i]; if(workerSocket!= null) { // 发给所有连接上服务器的客户 if(workerSocket.Connected) { workerSocke