经过上次的socket 通讯demo 未加入多线程的应用
https://blog.csdn.net/dongnihao/article/details/83989561( 上次的demo)
那么这次我们通过加入multithreading多线程来实现多个客户端给服务器发消息。
首先看服务器端的代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace 客户端czbk
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Socket socketSend;
private void btnStart_Click(object sender, EventArgs e)
{
//当点击开始监听的时候 在服务器端创建一个负责监听IP地址和端口号的Socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//获取ip地址第一个参数是指定socket对象使用的寻址方案,即IPV4或IPV6;
//第二个参数socket对象的套接字的类型,此处stream是表示流式套接字
//第三个参数socket对象支持的协议,TCP协议或UDP协议。
IPAddress ipaddress = IPAddress.Parse(txtIp.Text.Trim()); //获取文本框输入的IP地址
//将IP地址和端口号绑定到网络节点endpoint上
IPEndPoint endpoint = new IPEndPoint(ipaddress, int.Parse(txtPort.Text.Trim())); //获取文本框上输入的端口号
//监听绑定的网络节点
socketWatch.Bind(endpoint);// 端口号里也包含了本机的IP地址 使用了绑定
socketWatch.Listen(10);
Addmessage("Listen successfully!!! ");
//下面开启一个新线程
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
}
//将远程连接的客户端ip地址 和 socket 存入集合 这个我有点感觉像map
// Dictionary<string, string>是一个泛型
//他本身有集合的功能有时t 候可以把它看成数组
//他的结构是这样的:Dictionary<[key], [value]>
//他的特点是存入对象是需要与[key]值一一对应的存入该泛型
//通过某一个一定的[key]去找到对应的值 这边不好搞 我就不写了
//等待客户端的连接 并穿件一个负责通信的socket
Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
void Listen(object o)
{//因为只能被线程执行 所以我要写object o 然后再转化类型
Socket socketWatch = o as Socket;
//等待连接 创建一个负责通讯的socket 做一个类型转换16091007
while (true)
{
try
{
socketSend = socketWatch.Accept();
//这个是负责和客户端通信的socket
dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);
comboBox1.Items.Add(socketSend.RemoteEndPoint.ToString());
Addmessage(socketSend.RemoteEndPoint.ToString() + "." + "A User Link to the service");//remoteendpoint这个是拿到远程ip地址和端口号
//为什么写个循环呢 因为每个客户端和服务器都要重新创建一个新的连接 有几个客户端就有几个socket
// 用线程去运行 不要放在主线程里面 开启一个新线程
Thread th = new Thread(Receive);//开启一个新线程. 不停接受了客户端发送的消息
th.IsBackground = true;
th.Start(socketSend);
}
catch
{
}
}
}
void Receive(object o)
{//因为只能被线程执行 所以我要写object o 然后再转化类型
Socket socketSend = o as Socket;
while (true)
{ //客户端连接成功 服务器应该接受客户端发来的消息
try
{
byte[] buffer = new byte[1024 * 1024 * 2];
int r = socketSend.Receive(buffer);//
if (r == 0)
{
break;
}
string str = Encoding.UTF8.GetString(buffer, 0, r);//从0开始 解码r个
Addmessage(socketSend.RemoteEndPoint + ":" + str);
}
catch
{ //不显示给用户 就算有异常
}
}
}
void Addmessage(String str)
{
txtlog.AppendText(str+"\r\n");
}
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
//就是说在加载过程中 程序不会去检查这个多线程的错误
}
private void txtlog_TextChanged(object sender, EventArgs e)
{
}
private void txtIp_TextChanged(object sender, EventArgs e)
{
}
//服务器给客户端发消息
private void btnSend_Click(object sender, EventArgs e)
{
string str = txtMsg.Text;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
string ip = comboBox1.SelectedItem.ToString();
dicSocket[ip].Send(buffer);
}
private void textBox5_TextChanged(object sender, EventArgs e)
{
}
}
}
我们从服务器短的winform界面上看到,为了给不同的客户端发消息。我添加了一个combox下拉来选择。
再来看客户端的代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace 服务器端czbk
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Socket socketSend;
private void btnStart_Click(object sender, EventArgs e)
{
try
{
//创建负责通信的socket
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(txtServer.Text);
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
//获得要连接的远程服务器应用程序的ip地址和端口号
socketSend.Connect(point);
Addmessgae("Link Successfully ,welcome ! ");
//可能卡死 所以要开启多线程 不停 接受服务端信息
Thread th = new Thread(Receive);
th.IsBackground = true;
th.Start();
}
catch
{
}
}
void Receive( )
{//因为只能被线程执行 所以我要写object o 然后再转化类型ddddaawassda
while (true)
{
byte[] buffer = new byte[1024 * 1024 * 5];
//实际接收带的字节数
int r = socketSend.Receive(buffer);//
if (r == 0)
{
break;
}
string s = Encoding.UTF8.GetString(buffer, 0, r);//从0开始解码r个
Addmessgae(socketSend.RemoteEndPoint + ":" + s);
}
}
void Addmessgae(String str)
{
txtLog.AppendText(str + "\r\n");// z追加文本 然后换行
}
private void btnSend_Click(object sender, EventArgs e)
{
String str = txtMsg.Text.Trim();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);
}
private void txtLog_TextChanged(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
Form1 addnew = new Form1();
addnew.Show();
}
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
}
}
客户端这边基本和服务器端相同的,这边另外加一个button来实现添加客户端。