WebSocket全双工通讯链接,用于前台和后台自由发送信息
一.效果展示:
效果描述:
1.服务器充当管理员,给所有人发送信息,除服务器以外其他人都能接受到。
2.其他用户发送信息除自己以外其他用户和管理员全能接受到。
注意:图中打码处为服务器IP和端口,每个电脑都只能访问自己的服务器以及端口,用cmd打开管理员命令窗口,用如下代码 可以查看本机所有IP和端口
netstat -a
//或者
netstat -an
二.服务器代码:
public partial class MainForm : Form
{List<Socket> ClientProxSocketList = new List<Socket>();public MainForm(){InitializeComponent();}Socket proxSocket;//点击启动按钮private void btn_Start_Click(object sender, EventArgs e){//1 创建SocketSocket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//2 绑定端口Ipsocket.Bind(new IPEndPoint(IPAddress.Parse(txt_Ip.Text),int.Parse(txt_Port.Text)));//3 开启监听socket.Listen(1000); //链接:最大接收请求数,超出返回错误信息//4 开始接收客户端的链接ThreadPool.QueueUserWorkItem(new WaitCallback(this.AcceptClientConnect),socket);}//将远程连接的客户端的IP地址和Socket存入集合中Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();public void AcceptClientConnect(object socket){var serverSocket = socket as Socket;this.AppendTextToTxtLog("服务器开始接受客户端的链接。");while (true){//负责跟客户通信的SocketproxSocket = serverSocket.Accept();//将远程连接的客户端的IP地址和Socket存入集合中dicSocket.Add(proxSocket.RemoteEndPoint.ToString(),proxSocket);//将远程连接的客户端IP地址和端口存储下拉框中//cboUsers.Items.Add(proxSocket.RemoteEndPoint.ToString());this.AppendTextToTxtLog(string.Format("客户端:{0}链接上了",proxSocket.RemoteEndPoint.ToString()));ClientProxSocketList.Add(proxSocket);//不停的接收当前链接的客户端发送的信息// proxSocket.Receive();ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData),proxSocket);}}//接收客户端的消息public void ReceiveData(object socket){var proxSocket = socket as Socket;byte[] data = new byte[1024 * 1024 * 2];while (true){int len = 0;try{len = proxSocket.Receive(data, 0, data.Length, SocketFlags.None);}catch (Exception){//异常退出AppendTextToTxtLog(string.Format("客户端:{0}正常退出", proxSocket.RemoteEndPoint.ToString()));ClientProxSocketList.Remove(proxSocket);return;}if(len <= 0){//客户端正常退出AppendTextToTxtLog(string.Format("客户端:{0}正常退出", proxSocket.RemoteEndPoint.ToString()));ClientProxSocketList.Remove(proxSocket);return;//让方法结束,终结当前接受客户端数据的异步线程}//把接收到的数据放到文本框中string str = Encoding.UTF8.GetString(data,0,len);AppendTextToTxtLog(string.Format("接收到客户端:{0}的消息是:{1}",proxSocket.RemoteEndPoint.ToString(),str));//服务器转发信息,除发送方以外,转发信息byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);foreach (var item in dicSocket){if (item.Key != proxSocket.RemoteEndPoint.ToString())item.Value.Send(buffer);}}}//往日志的文本框上追加数据public void AppendTextToTxtLog(string txt){if (txt_Cont.InvokeRequired){txt_Cont.Invoke(new Action<string>(s =>{this.txt_Cont.Text = string.Format("{0}\r\n{1}", s, txt_Cont.Text);}),txt);}else{this.txt_Cont.Text = string.Format("{0}\r\n{1}", txt, txt_Cont.Text);}}//服务器给客户端发送信息private void btn_Send_Click(object sender, EventArgs e){#region//foreach (var proxSocket in ClientProxSocketList)//{// if (proxSocket.Connected)// {// byte[] data = Encoding.Default.GetBytes(txt_Msg.Text);// proxSocket.Send(data, 0, data.Length, SocketFlags.None);// }//}#endregionstring str = txt_Msg.Text;byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);//获取用户在下拉框中选择的IP地址//string ip = cboUsers.SelectedItem.ToString();foreach (var item in dicSocket){//if(item.Key != proxSocket.RemoteEndPoint.ToString())item.Value.Send(buffer);}//proxSocket.Send(buffer);}
}
三.客户端代码:
public partial class ClientForm : Form
{public ClientForm(){InitializeComponent();}Socket socketSend;//点击连接private void btn_Link_Click(object sender, EventArgs e){//创建负责通信的SocketsocketSend = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);IPAddress ip = IPAddress.Parse(lab_Ip.Text);IPEndPoint point = new IPEndPoint(ip,Convert.ToInt32(lab_Port.Text));socketSend.Connect(point);ShowMsg("连接成功");//开启一个线程不停接受服务器发送来的信息Thread th = new Thread(Recive);th.IsBackground = true;th.Start();}//不停接受服务器发来的消息void Recive(){while (true){byte[] buffer = new byte[1024 * 1024 * 3];//实际接受到的有效字节int r = socketSend.Receive(buffer);if(r <= 0){break;}string s = Encoding.UTF8.GetString(buffer,0,r);ShowMsg(socketSend.RemoteEndPoint+":"+s);}}void ShowMsg(string str){txt_Cont.AppendText(str + "\r\n");}//点击发送按钮,客户端给服务器发送消息private void btn_Send_Click(object sender, EventArgs e){string str = txt_Msg.Text.Trim();byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);socketSend.Send(buffer);}
}
四.总结&猜想
这里的服务器转发只用了一个Dictionary存储了所有连接服务器的Socket。如果要做一个更好的单独会话,就在数据库好友的链接表里面,记录好端口和IP,每次选择好友查询数据库,单独发送给好友
五.学习链接:
CSDN C# Socket 会话思路与实现
BiLibili Winform应用程序_多线程和socket网络编程
吐槽:
就很怪,现在发布文章,字数不多还提示推荐受影响。。。
CSDN路走窄了啊,浓缩的都是精华好吧。
再这样下去,我只能放弃CSDN去博客园了。
吐槽:
就很怪,现在发布文章,字数不多还提示推荐受影响。。。
CSDN路走窄了啊,浓缩的都是精华好吧。
再这样下去,我只能放弃CSDN去博客园了。
吐槽:
就很怪,现在发布文章,字数不多还提示推荐受影响。。。
CSDN路走窄了啊,浓缩的都是精华好吧。
再这样下去,我只能放弃CSDN去博客园了。
吐槽:
就很怪,现在发布文章,字数不多还提示推荐受影响。。。
CSDN路走窄了啊,浓缩的都是精华好吧。
再这样下去,我只能放弃CSDN去博客园了。