总结:
服务器端先创建一个socketwatch监控等待客户端连接,客户端连接后循环socketwatch.accept()创建多个通信线程,每个通信线程再创建新的数据处理线程,数据必须循环接收
客户端没有socketwatch,直接创建socket,连接用connect(),发送用socket.send(),接收用receive(),数据也是循环接收的
一、服务器端单线程流程:
//服务器创建一个socket用于监听 Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //设置ip和端口 IPAddress ip = IPAddress.Any; IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(textBox2.Text)); //绑定,即监听 socketwatch.Bind(endpoint); //设置监听数量 socketwatch.Listen(10); Msger("监听成功!"+"\n\r"); //等待客户端连接,并创建一个负责通信的socket, 单线程的话会一直等待accept(),卡死 Socket socketsend = socketwatch.Accept(); //接收远程连接的ip信息 Msger(socketsend.RemoteEndPoint.ToString()+" 连接进来");
服务器端多线程: 一个监听socket可以创建多个通信socket,监听socket循环创建多个通信socket线程,其中每个通信socket再创建一个线程处理信息,预防卡死
private void button1_Click(object sender, EventArgs e) { //服务器创建一个socket用于监听 Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //设置ip和端口 IPAddress ip = IPAddress.Any; IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(textBox2.Text)); //绑定,即监听 socketwatch.Bind(endpoint); //设置监听数量 socketwatch.Listen(10); Msger("监听成功!" + "\n\r"); //创建线程预防卡死 Thread th = new Thread(Listen); th.IsBackground = true; th.Start(socketwatch);// 传入监听进程 } //监听socket循环创建多个通信socket线程,其中每个通信socket再创建一个线程处理信息,预防卡死 private void Listen(object s) { //类型转换,as转换成功返回值否则NULL Socket socketwatch = s as Socket; //等待客户端连接,并创建一个负责通信的socket while (true) { Socket socketsend = socketwatch.Accept(); Msger(socketsend.RemoteEndPoint.ToString() + " 连接进来" + "\t\r\n"); //创建一个新的线程处理客户端发送过来的信息,否则一个socket就堵塞 Thread th = new Thread(Operater); th.IsBackground = true; th.Start(socketsend); } } /// <summary> /// 信息处理线程 /// </summary> /// <param name="s">socket返回客户端信息</param> public void Operater(object s) { Socket socketsend = s as Socket; //必须循环接收消息 while (true) { //创建字节数组并接受传过来的数据,返回int为实际使用值 byte[] receive = new byte[1024 * 1024 * 2]; int realr = socketsend.Receive(receive); //判断客户端发送的内容,如果为0则停止循环 if (realr == 0) { break; } //解码 string text = Encoding.UTF8.GetString(receive, 0, realr); //写入textbox Msger(text); } } public void Msger(string ms) { textBox3.AppendText(ms + "\n\r"); //追加方式 }
二、客户端简单流程:
private void button4_Click(object sender, EventArgs e) { //创建socket socketcustomsend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //设置ip和port IPAddress ip = IPAddress.Parse(textBox5.Text); IPEndPoint ipendpoint = new IPEndPoint(ip, Convert.ToInt32(textBox6.Text)); //连接 socketcustomsend.Connect(ipendpoint); textBox4.Text = "连接成功!"; //创建进程接受服务器传来的信息 Thread th = new Thread(CustomReceive); th.IsBackground = true; th.Start(socketcustomsend); } /// <summary> /// 循环接受服务器传来的信息 /// </summary> /// <param name="s">通信的socket</param> public void CustomReceive(object s) { while (true) //循环接收信息 { Socket socketcustomsend = s as Socket; byte[] b = new byte[1024 * 1024 * 5]; int r = socketcustomsend.Receive(b); if (r==0) //0表示服务器端关闭 { break; } textBox4.Text = Encoding.UTF8.GetString(b, 0, r); } }
三、通信的例子
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace socket通信 { public partial class socket练习 : Form { public socket练习() { InitializeComponent(); Control.CheckForIllegalCrossThreadCalls = false; } private void label1_Click(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { //服务器创建一个socket用于监听 Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //设置ip和端口 IPAddress ip = IPAddress.Any; IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(textBox2.Text)); //绑定,即监听 socketwatch.Bind(endpoint); //设置监听数量 socketwatch.Listen(10); Msger("监听成功!" + "\n\r"); //创建线程预防卡死 Thread th = new Thread(Listen); th.IsBackground = true; th.Start(socketwatch);// 传入监听进程 } //监听socket循环创建多个通信socket线程,其中每个通信socket再创建一个线程处理信息,预防卡死 // 全局服务器端通信socket Socket socketsend; Dictionary<string, Socket> sdic = new Dictionary<string, Socket>(); private void Listen(object s) { //类型转换,as转换成功返回值否则NULL Socket socketwatch = s as Socket; //等待客户端连接,并创建一个负责通信的socket while (true) { socketsend = socketwatch.Accept(); //将socket与ip信息放入字典集合 sdic.Add(socketsend.RemoteEndPoint.ToString(), socketsend); //加入combox列表 comboBox1.Items.Add(socketsend.RemoteEndPoint.ToString()); //让combox显示当前连接的socket comboBox1.SelectedItem= socketsend.RemoteEndPoint.ToString(); Msger(socketsend.RemoteEndPoint.ToString() + " 连接进来了" + "\t\r\n"); //创建一个新的线程处理客户端发送过来的信息,否则一个socket就堵塞 Thread th = new Thread(Operater); th.IsBackground = true; th.Start(socketsend); } } /// <summary> /// 信息处理线程 /// </summary> /// <param name="s">socket返回客户端信息</param> public void Operater(object s) { Socket socketsend = s as Socket; //必须循环接收消息 while (true) { //创建字节数组并接受传过来的数据,返回int为实际使用值 byte[] receive = new byte[1024 * 1024 * 10]; int realr = socketsend.Receive(receive); //判断客户端发送的内容,如果为0则停止循环 if (realr == 0) { break; } //用文件头判断传过来的是文字信息或文件的各种类型,0-文字信息 1-文件 if (receive[0]==0) { //解码 string text = Encoding.UTF8.GetString(receive, 1, realr-1); //写入textbox Msger(text); } else if(receive[0]==1) //文件则保存 { SaveFileDialog sf = new SaveFileDialog(); sf.Filter = "所有文件|*.*"; sf.ShowDialog(this); //注意this用法 using (FileStream fs=new FileStream(sf.FileName,FileMode.Create,FileAccess.Write)) { fs.Write(receive, 1, realr-1); //-1去掉标志头 } } } } public void Msger(string ms) { textBox3.AppendText(ms + "\n"); //追加方式 } private void textBox1_TextChanged(object sender, EventArgs e) { } private void textBox2_TextChanged(object sender, EventArgs e) { } private void label5_Click(object sender, EventArgs e) { } private void label6_Click(object sender, EventArgs e) { } //客户端socket Socket socketcustomsend; private void button4_Click(object sender, EventArgs e) { //创建socket socketcustomsend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //设置ip和port IPAddress ip = IPAddress.Parse(textBox5.Text); IPEndPoint ipendpoint = new IPEndPoint(ip, Convert.ToInt32(textBox6.Text)); //连接 socketcustomsend.Connect(ipendpoint); textBox4.Text = "连接成功!"; //创建进程接受服务器传来的信息 Thread th = new Thread(CustomReceive); th.IsBackground = true; th.Start(socketcustomsend); } /// <summary> /// 循环接受服务器传来的信息 /// </summary> /// <param name="s">通信的socket</param> public void CustomReceive(object s) { while (true) //循环接收信息 { Socket socketcustomsend = s as Socket; byte[] b = new byte[1024 * 1024 * 5]; int r = socketcustomsend.Receive(b); if (r==0) //0表示服务器端关闭 { break; } textBox4.Text = Encoding.UTF8.GetString(b, 0, r); } } private void button2_Click(object sender, EventArgs e) { //准备数据 byte[] b = Encoding.UTF8.GetBytes(textBox4.Text); //加入识别头0 List<byte> nb = new List<byte>(); nb.Add(0); nb.AddRange(b); byte[] sb= nb.ToArray(); //发送 socketcustomsend.Send(sb); } private void button6_Click(object sender, EventArgs e) { textBox3.Clear(); } private void button5_Click(object sender, EventArgs e) { OpenFileDialog of = new OpenFileDialog(); of.Multiselect = false; of.Filter = "所有文件|*.*"; of.ShowDialog(); textBox7.Text = of.FileName; } private void button3_Click(object sender, EventArgs e) { using (FileStream fs = new FileStream(textBox7.Text, FileMode.Open, FileAccess.Read)) { byte[] b = new byte[1024 * 1024 * 10]; //返回真实使用数 int r = fs.Read(b, 0, b.Length); //添加文件类型识别头,list与array互相转换 List<byte> newbyte = new List<byte>(); newbyte.Add(1);//1代表文件 newbyte.AddRange(b);//将b中元素添加,add()为整个添加 byte[] nb=newbyte.ToArray(); //发送真实大小数据, 为r+1 socketcustomsend.Send(nb,0,r+1,SocketFlags.None); } } private void button7_Click(object sender, EventArgs e) { sdic[comboBox1.SelectedItem.ToString()].Send(Encoding.UTF8.GetBytes(textBox3.Text)); } } }