(C#:Socket)简单的服务端与客户端通信。
要求:
1.可以完成一对一的通信;
2.实现服务端对客户端一对多的选择发送;
3.可以实现服务端的群发功能;
4.可以实现客户端文件的发送;
要点:
服务器端:
第一步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第二步:建立一个Socket对像;
第三步:用socket对像的Bind()方法绑定EndPoint;
第四步:用socket对像的Listen()方法开始监听;
第五步:接受到客户端的连接,用socket对像的Accept()方法创建新的socket对像用于和请求的客户端进行通信;
第六步:通信结束后一定记得关闭socket;
客户端:
第一步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第二步:建立一个Socket对像;
第三步:用socket对像的Connect()方法以上面建立的EndPoint对像做为参数,向服务器发出连接请求;
第四步:如果连接成功,就用socket对像的Send()方法向服务器发送信息;
第五步:用socket对像的Receive()方法接受服务器发来的信息 ;
第六步:通信结束后一定记得关闭socket;
服务端代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Net; using System.Net.Sockets; using System.Threading; using System.IO; namespace Socket_ServerAndClient { public partial class Form1 : Form { public Form1() { InitializeComponent(); TextBox.CheckForIllegalCrossThreadCalls = false; } Thread threadWatch = null; Socket socketWatch = null; /// <summary> /// 创建服务 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { socketWatch = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); IPAddress address = IPAddress.Parse(txtIP.Text.Trim()); IPEndPoint endpoint = new IPEndPoint(address,int.Parse(txtPort.Text.Trim())); socketWatch.Bind(endpoint); socketWatch.Listen(10); threadWatch = new Thread(WatchConnection); threadWatch.IsBackground = true; threadWatch.Start(); ShowMsg("服务器监听成功......"); } //Socket sokConnection = null; Dictionary<string, Socket> dict = new Dictionary<string, Socket>(); Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>(); /// <summary> /// 监听客户端的请求方法 /// </summary> /// <param name="obj"></param> private void WatchConnection(object obj) { while (true) { // 负责通信的套接字 Socket sokConnection = socketWatch.Accept(); lb_Online.Items.Add(sokConnection.RemoteEndPoint.ToString()); dict.Add(sokConnection.RemoteEndPoint.ToString(),sokConnection); //创建通信线程 ParameterizedThreadStart pts = new ParameterizedThreadStart(RecMsg);// 委托 Thread thr = new Thread(pts); thr.IsBackground = true; thr.Start(sokConnection); dictThread.Add(sokConnection.RemoteEndPoint.ToString(),thr); ShowMsg("客户端连接成功......"+sokConnection.RemoteEndPoint.ToString()); } } /// <summary> /// 服务端负责监听客户端发送消息的方法 /// </summary> void RecMsg(object socketClient) { Socket socketClients = socketClient as Socket; while (true) { byte[] arrMsgRec = new byte[1024 * 1024 * 2]; int length = -1; try { length = socketClients.Receive(arrMsgRec); } catch (SocketException ex) { ShowMsg("异常:" + ex.Message); // 从 通信套接字 集合中删除被中断连接的套接字对象 dict.Remove(socketClients.RemoteEndPoint.ToString()); // 从 通信线程 集合中删除被中断连接的套接字对象 dictThread.Remove(socketClients.RemoteEndPoint.ToString()); // 从 列表 中移除 IP&Port lb_Online.Items.Remove(socketClients.RemoteEndPoint.ToString()); break; } catch (Exception ex) { ShowMsg("异常:" + ex.Message); break; } // 判断第一个发送过来的数据如果是1,则代表发送过来的是文本数据 if (arrMsgRec[0] == 0) { string strMsgRec = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length-1); ShowMsg(strMsgRec); } // 若是1则发送过来的是文件数据(文档,图片,视频等。。。) else if(arrMsgRec[0] == 1) { // 保存文件选择框对象 SaveFileDialog sfd = new SaveFileDialog(); // 选择文件路径 if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { // 获得保存文件的路径 string fileSavePath = sfd.FileName; // 创建文件流,然后让文件流根据路径创建一个文件 using (FileStream fs = new FileStream(fileSavePath, FileMode.Create)) { fs.Write(arrMsgRec, 1, length - 1); ShowMsg("文件保存成功:"+fileSavePath); } } } } } private void ShowMsg(string p) { txtMsg.AppendText(p+"\r\n"); } /// <summary> /// 发送消息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Send_Click_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(lb_Online.Text)) { MessageBox.Show("请选择发送的好友!!!"); } else { string strMsg = tb_Msg_Send.Text.Trim(); byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); string strClientKey = lb_Online.Text; try { dict[strClientKey].Send(arrMsg); ShowMsg("发送了数据出去:"+strMsg); } catch (SocketException ex) { ShowMsg("发送时异常:" + ex.Message); } catch(Exception ex) { ShowMsg("发送时异常:" + ex.Message); } // sokConnection.Send(arrMsg); ShowMsg("发送了数据出去:"+strMsg); } } /// <summary> /// 群发消息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void SendToAll_Click(object sender, EventArgs e) { string strMsg = txtMsg.Text.Trim(); byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); foreach (Socket item in dict.Values) { item.Send(arrMsg); } ShowMsg("群发完毕!!!:)"); } } }
客户端代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Net; using System.Net.Sockets; using System.Threading; using System.IO; namespace Socket_Client { public partial class Form1 : Form { public Form1() { InitializeComponent(); TextBox.CheckForIllegalCrossThreadCalls = false; } Thread threadRec = null; Socket socketClient = null; private void btn_Connect_Click(object sender, EventArgs e) { IPAddress address = IPAddress.Parse(tb_IP.Text.Trim()); IPEndPoint endport = new IPEndPoint(address,int.Parse(tb_Port.Text.Trim())); socketClient = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); socketClient.Connect(endport); threadRec = new Thread(RecMsg); threadRec.IsBackground = true; threadRec.Start(); } void RecMsg() { while (true) { byte[] arrMsgRec = new byte[1024*1024*2]; int length = socketClient.Receive(arrMsgRec); string strMsgRec = System.Text.Encoding.UTF8.GetString(arrMsgRec,0,length); ShowMsg(strMsgRec); } } private void ShowMsg(string msg) { tb_Msg.AppendText(msg+"\r\n"); } private void btnSendMsg_Click(object sender, EventArgs e) { string strMsg = txtMsgSend.Text.Trim(); byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); byte[] arrMsgSend = new byte[arrMsg.Length]; // 添加标识位,0代表发送的是文字 arrMsgSend[0] = 0; Buffer.BlockCopy(arrMsg, 0, arrMsgSend, 1, arrMsg.Length); socketClient.Send(arrMsg); ShowMsg("I say:"+strMsg); } /// <summary> /// 选择文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btChoseFile_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { txtFilePath.Text = ofd.FileName; } } /// <summary> /// 发送文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btSendFile_Click(object sender, EventArgs e) { using (FileStream fs = new FileStream()) { byte[] arrFile = new byte[1024*1024*2]; int length = fs.Read(arrFile, 0, arrFile.Length); byte[] arrFileSend = new byte[length+1]; arrFileSend[0] = 1;// 代表文件数据 // 将数组 arrFile 里的数据从第零个数据拷贝到 数组 arrFileSend 里面,从第1个开始,拷贝length个数据 Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length); socketClient.Send(arrFileSend); } } } }
程序运行截图: