Socket 编程,一个服务器,多个客户端,互相通信
关于一个 Scoket 通信的基本代码和一个基本的通信
实现一个服务器和N个客户端的互相聊天
Server:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Net;//Endpoint using System.Net.Sockets;//包含套接字 using System.Text; using System.Windows.Forms; using System.Threading; using System.IO; namespace Server { public partial class Form1 : Form { public Form1() { InitializeComponent(); TextBox.CheckForIllegalCrossThreadCalls = false;//关闭跨线程修改控件检查 } Socket sokWatch = null;//负责监听 客户端段 连接请求的 套接字 Thread threadWatch = null;//负责 调用套接字, 执行 监听请求的线程 //开启监听 按钮 private void btnStartListen_Click(object sender, EventArgs e) { //实例化 套接字 (ip4寻址协议,流式传输,TCP协议) sokWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //创建 ip对象 IPAddress address = IPAddress.Parse(txtIP.Text.Trim()); //创建网络节点对象 包含 ip和port IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim())); //将 监听套接字 绑定到 对应的IP和端口 sokWatch.Bind(endpoint); //设置 监听队列 长度为10(同时能够处理 10个连接请求) sokWatch.Listen(10); threadWatch = new Thread(StartWatch); threadWatch.IsBackground = true; threadWatch.Start(); txtShow.AppendText("启动服务器成功......\r\n"); } //Dictionary<string, Socket> dictSocket = new Dictionary<string, Socket>(); Dictionary<string, ConnectionClient> dictConn = new Dictionary<string, ConnectionClient>(); bool isWatch = true; #region 1.被线程调用 监听连接端口 /// <summary> /// 被线程调用 监听连接端口 /// </summary> void StartWatch() { while (isWatch) { //threadWatch.SetApartmentState(ApartmentState.STA); //监听 客户端 连接请求,但是,Accept会阻断当前线程 Socket sokMsg = sokWatch.Accept();//监听到请求,立即创建负责与该客户端套接字通信的套接字 ConnectionClient connection = new ConnectionClient(sokMsg, ShowMsg, RemoveClientConnection); //将负责与当前连接请求客户端 通信的套接字所在的连接通信类 对象 装入集合 dictConn.Add(sokMsg.RemoteEndPoint.ToString(), connection); //将 通信套接字 加入 集合,并以通信套接字的远程IpPort作为键 //dictSocket.Add(sokMsg.RemoteEndPoint.ToString(), sokMsg); //将 通信套接字的 客户端IP端口保存在下拉框里 cboClient.Items.Add(sokMsg.RemoteEndPoint.ToString()); ShowMsg("接收连接成功......"); //启动一个新线程,负责监听该客户端发来的数据 //Thread threadConnection = new Thread(ReciveMsg); //threadConnection.IsBackground = true; //threadConnection.Start(sokMsg); } } #endregion bool isRec = true;//与客户端通信的套接字 是否 监听消息 #region 发送消息 到指定的客户端 -btnSend_Click //发送消息 到指定的客户端 private void btnSend_Click(object sender, EventArgs e) { //byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(txtInput.Text.Trim()); //从下拉框中 获得 要哪个客户端发送数据 string connectionSokKey = cboClient.Text; if (!string.IsNullOrEmpty(connectionSokKey)) { //从字典集合中根据键获得 负责与该客户端通信的套接字,并调用send方法发送数据过去 dictConn[connectionSokKey].Send(txtInput.Text.Trim()); //sokMsg.Send(arrMsg); } else { MessageBox.Show("请选择要发送的客户端~~"); } } #endregion //发送闪屏!! private void btnShack_Click(object sender, EventArgs e) { string connectionSokKey = cboClient.Text; if (!string.IsNullOrEmpty(connectionSokKey)) { dictConn[connectionSokKey].SendShake(); } else { MessageBox.Show("请选择要发送的客户端~~"); } } //群闪 private void btnShackAll_Click(object sender, EventArgs e) { foreach (ConnectionClient conn in dictConn.Values) { conn.SendShake(); } } #region 2 移除与指定客户端的连接 +void RemoveClientConnection(string key) /// <summary> /// 移除与指定客户端的连接 /// </summary> /// <param name="key">指定客户端的IP和端口</param> public void RemoveClientConnection(string key) { if (dictConn.ContainsKey(key)) { dictConn.Remove(key); cboClient.Items.Remove(key); } } #endregion //选择要发送的文件 private void btnChooseFile_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { txtFilePath.Text = ofd.FileName; } } //发送文件 private void btnSendFile_Click(object sender, EventArgs e) { //拿到下拉框中选中的客户端IPPORT string key = cboClient.Text; if (!string.IsNullOrEmpty(key)) { dictConn[key].SendFile(txtFilePath.Text.Trim()); } } #region 向文本框显示消息 -void ShowMsg(string msgStr) /// <summary> /// 向文本框显示消息 /// </summary> /// <param name="msgStr">消息</param> public void ShowMsg(string msgStr) { txtShow.AppendText(msgStr + "\r\n"); } #endregion private void btnSendMsgAll_Click(object sender, EventArgs e) { foreach (ConnectionClient conn in dictConn.Values) { conn.Send(txtInput.Text.Trim()); } } } }
新建一个中间类, ConnectionClient
using System; using System.Collections.Generic; using System.Threading; using System.Net; using System.Net.Sockets; using System.Text; using System.IO; namespace Server { /// <summary> /// 与客户端的 连接通信类(包含了一个 与客户端 通信的 套接字,和线程) /// </summary> public class ConnectionClient { Socket sokMsg; DGShowMsg dgShowMsg;//负责 向主窗体文本框显示消息的方法委托 DGShowMsg dgRemoveConnection;// 负责 从主窗体 中移除 当前连接 Thread threadMsg; #region 构造函数 /// <summary> /// /// </summary> /// <param name="sokMsg">通信套接字</param> /// <param name="dgShowMsg">向主窗体文本框显示消息的方法委托</param> public ConnectionClient(Socket sokMsg, DGShowMsg dgShowMsg, DGShowMsg dgRemoveConnection) { this.sokMsg = sokMsg; this.dgShowMsg = dgShowMsg; this.dgRemoveConnection = dgRemoveConnection; this.threadMsg = new Thread(RecMsg); this.threadMsg.IsBackground = true; this.threadMsg.Start(); } #endregion bool isRec = true; #region 02负责监听客户端发送来的消息 void RecMsg() { while (isRec) { try { byte[] arrMsg = new byte[1024 * 1024 * 2]; //接收 对应 客户端发来的消息 int length = sokMsg.Receive(arrMsg); //将接收到的消息数组里真实消息转成字符串 string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg, 0, length); //通过委托 显示消息到 窗体的文本框 dgShowMsg(strMsg); } catch (Exception ex) { isRec = false; //从主窗体中 移除 下拉框中对应的客户端选择项,同时 移除 集合中对应的 ConnectionClient对象 dgRemoveConnection(sokMsg.RemoteEndPoint.ToString()); } } } #endregion #region 03向客户端发送消息 /// <summary> /// 向客户端发送消息 /// </summary> /// <param name="strMsg"></param> public void Send(string strMsg) { byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); byte[] arrMsgFinal = new byte[arrMsg.Length+1]; arrMsgFinal[0] = 0;//设置 数据标识位等于0,代表 发送的是 文字 arrMsg.CopyTo(arrMsgFinal, 1); sokMsg.Send(arrMsgFinal); } #endregion #region 04向客户端发送文件数据 +void SendFile(string strPath) /// <summary> /// 04向客户端发送文件数据 /// </summary> /// <param name="strPath">文件路径</param> public void SendFile(string strPath) { //通过文件流 读取文件内容 using (FileStream fs = new FileStream(strPath, FileMode.OpenOrCreate)) { byte[] arrFile = new byte[1024 * 1024 * 2]; //读取文件内容到字节数组,并 获得 实际文件大小 int length = fs.Read(arrFile, 0, arrFile.Length); //定义一个 新数组,长度为文件实际长度 +1 byte[] arrFileFina = new byte[length + 1]; arrFileFina[0] = 1;//设置 数据标识位等于1,代表 发送的是文件 //将 文件数据数组 复制到 新数组中,下标从1开始 //arrFile.CopyTo(arrFileFina, 1); Buffer.BlockCopy(arrFile, 0, arrFileFina, 1, length); //发送文件数据 sokMsg.Send(arrFileFina);//, 0, length + 1, SocketFlags.None); } } #endregion #region 05向客户端发送闪屏 /// <summary> /// 向客户端发送闪屏 /// </summary> /// <param name="strMsg"></param> public void SendShake() { byte[] arrMsgFinal = new byte[1]; arrMsgFinal[0] = 2; sokMsg.Send(arrMsgFinal); } #endregion #region 06关闭与客户端连接 /// <summary> /// 关闭与客户端连接 /// </summary> public void CloseConnection() { isRec = false; } #endregion } }
最后就是我们的客户端了噢.
Client:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Net.Sockets; using System.Net; using System.Threading; using System.Windows.Forms; using System.IO; namespace Client { public partial class Form1 : Form { public Form1() { InitializeComponent(); TextBox.CheckForIllegalCrossThreadCalls = false; } Socket sokClient = null;//负责与服务端通信的套接字 Thread threadClient = null;//负责 监听 服务端发送来的消息的线程 bool isRec = true;//是否循环接收服务端数据 private void btnConnect_Click(object sender, EventArgs e) { //实例化 套接字 sokClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //创建 ip对象 IPAddress address = IPAddress.Parse(txtIP.Text.Trim()); //创建网络节点对象 包含 ip和port IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim())); //连接 服务端监听套接字 sokClient.Connect(endpoint); //创建负责接收 服务端发送来数据的 线程 threadClient = new Thread(ReceiveMsg); threadClient.IsBackground = true; //如果在win7下要通过 某个线程 来调用 文件选择框的代码,就需要设置如下 threadClient.SetApartmentState(ApartmentState.STA); threadClient.Start(); } /// <summary> /// 接收服务端发送来的消息数据 /// </summary> void ReceiveMsg() { while (isRec) { byte[] msgArr = new byte[1024 * 1024 * 1];//接收到的消息的缓冲区 int length=0; //接收服务端发送来的消息数据 length =sokClient.Receive(msgArr);//Receive会阻断线程 if (msgArr[0] == 0)//发送来的是文字 { string strMsg = System.Text.Encoding.UTF8.GetString(msgArr, 1, length - 1); txtShow.AppendText(strMsg + "\r\n"); } else if (msgArr[0] == 1) { //发送来的是文件 SaveFileDialog sfd = new SaveFileDialog(); //弹出文件保存选择框 if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { //创建文件流 using (FileStream fs = new FileStream(sfd.FileName, FileMode.OpenOrCreate)) { fs.Write(msgArr, 1, length - 1); MessageBox.Show("文件保存成功!"); } } } else if (msgArr[0] == 2) { ShakeWindow(); } } } /// <summary> /// 闪屏 /// </summary> private void ShakeWindow() { Random ran = new Random(); //保存 窗体原坐标 System.Drawing.Point point = this.Location; for (int i = 0; i < 30; i++) { //随机 坐标 this.Location = new System.Drawing.Point(point.X + ran.Next(8), point.Y + ran.Next(8)); System.Threading.Thread.Sleep(15);//休息15毫秒 this.Location = point;//还原 原坐标(窗体回到原坐标) System.Threading.Thread.Sleep(15);//休息15毫秒 } } //发送消息 private void btnSend_Click(object sender, EventArgs e) { byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(txtInput.Text.Trim()); sokClient.Send(arrMsg); } } }
以上代码就能实现一个简单的 Scoket 通信
实现了一个服务器和N个客户端的交互,能做成一个简单的聊天程序
Socket 编程,一个服务器,多个客户端,互相通信相关推荐
- 服务器没有响应客户端,socket编程某些服务器对某些客户端没有响应的问题!!...
socket编程某些服务器对某些客户端没有响应的问题!! 我是这么用的t=serversocket(inetaddress,2); while(true){ t=y.accept(); out=new ...
- Python3进阶--Socket编程、多线程(创建方式、线程通信、线程锁、线程池)
第一章 变量.常用循环体.代码结构.代码练习 第二章 列表.元组等数据结构.字符串驻留机制及字符串格式化操作 第三章 函数.面向对象.文件操作.深浅拷贝.模块.异常及捕获 第四章 项目打包.类和对象高 ...
- Socket代码实现服务端 和 客户端之间通信
服务端代码 // Socket_connection.cpp : 此文件包含 "main" 函数.程序执行将在此处开始并结束. // #ifndef UNICODE #define ...
- Linux下网络socket编程——实现服务器(select)与多个客户端通信
一.关于socket通信 服务器端工作流程: 调用 socket() 函数创建套接字 用 bind() 函数将创建的套接字与服务端IP地址绑定 调用listen()函数监听socket() 函数创建的 ...
- c语言接受socket发送尾部有乱码,C语言socket编程,服务器和一个客户端连接时,服务器能正常收到信息,2个以上就出现BUG了...
新手刚刚接触这个,建立的是控制台的32位程序. 程序思路服务器监听,每次连接,创建一个进程,全权处理该客户端的通信(不用考虑资源浪费问题). 服务器监听部分: while (true) { sockC ...
- OSI七层、TCP/IP五层、UDP、TCP的socket编程(服务端及客户端)、字节序转换、多进程以及多线程服务端的实现
1.网络以覆盖范围划分:局域网/城域网/广域网 互联网/因特网 以太网/令牌环网--组网方式 2.在网络中必须能够为一表示每一台主机,才能实现点到点的精确通信 IP地址: ...
- 基于Socket编程下 实现Linux-Linux、Linux-Windows tcp通信
文章目录 前言 一.Linux - Linux 服务器 server 客户端 client 通信实操 二.socket编程在windows和linux下的区别 三.Windows - Linux 四. ...
- SOCKET编程-时间服务器和客户端的实现
文章目录 UNIX_NET 获取服务器时间 connect函数 获取时间客户端程序实现 获取时间服务器实现 小技巧 宏定义的使用&&变参函数的宏定义实现 源码地址 UNIX_NET 获 ...
- python实现邮件客户端_python socket实现web服务器,邮件客户端
本博客是针对,<计算机网络自顶向下方法>一书第二章后面套接字编程作业, 所有代码均已上传至我的github:https://github.com/inspurer/ComputerNetw ...
最新文章
- 刚发现的 Wi-Fi 安全漏洞,可能危及全球所有设备!
- 循环遍历Java字符串字符的规范方法——类似python for ch in string
- mybatis中$和#的区别
- 华为手机asph啥机型_华为正式宣布!19款机型开启新系统内测,你的手机榜首有名吗?...
- 三层架构——配置文件
- c语言记录五个数组编程,C语言经典编程之数组
- c,c++中字符串处理函数strtok,strstr,strchr,strsub
- UNIX网络编程笔记(6):I/O复用之select函数
- angular安装记录
- Android Junit测试
- Django 前后端数据传输、ajax、分页器
- React Native之APK文件签名及打包
- MatConvNet中关于vl_simplenn_display的一些分析
- asp毕业设计——基于asp+access的工资管理系统设计与实现(毕业论文+程序源码)——工资管理系统
- 微信小程序 上传头像截图功能
- jar构建docker镜像_将jar包打包为docker镜像
- 毕设 疲劳驾驶检测系统 python
- Pytest如何查找用例耗时最长的N个
- 记录学习java 所用的一些工具
- android 集成分享!!