关于一个 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 编程,一个服务器,多个客户端,互相通信相关推荐

  1. 服务器没有响应客户端,socket编程某些服务器对某些客户端没有响应的问题!!...

    socket编程某些服务器对某些客户端没有响应的问题!! 我是这么用的t=serversocket(inetaddress,2); while(true){ t=y.accept(); out=new ...

  2. Python3进阶--Socket编程、多线程(创建方式、线程通信、线程锁、线程池)

    第一章 变量.常用循环体.代码结构.代码练习 第二章 列表.元组等数据结构.字符串驻留机制及字符串格式化操作 第三章 函数.面向对象.文件操作.深浅拷贝.模块.异常及捕获 第四章 项目打包.类和对象高 ...

  3. Socket代码实现服务端 和 客户端之间通信

    服务端代码 // Socket_connection.cpp : 此文件包含 "main" 函数.程序执行将在此处开始并结束. // #ifndef UNICODE #define ...

  4. Linux下网络socket编程——实现服务器(select)与多个客户端通信

    一.关于socket通信 服务器端工作流程: 调用 socket() 函数创建套接字 用 bind() 函数将创建的套接字与服务端IP地址绑定 调用listen()函数监听socket() 函数创建的 ...

  5. c语言接受socket发送尾部有乱码,C语言socket编程,服务器和一个客户端连接时,服务器能正常收到信息,2个以上就出现BUG了...

    新手刚刚接触这个,建立的是控制台的32位程序. 程序思路服务器监听,每次连接,创建一个进程,全权处理该客户端的通信(不用考虑资源浪费问题). 服务器监听部分: while (true) { sockC ...

  6. OSI七层、TCP/IP五层、UDP、TCP的socket编程(服务端及客户端)、字节序转换、多进程以及多线程服务端的实现

    1.网络以覆盖范围划分:局域网/城域网/广域网   互联网/因特网   以太网/令牌环网--组网方式 2.在网络中必须能够为一表示每一台主机,才能实现点到点的精确通信            IP地址: ...

  7. 基于Socket编程下 实现Linux-Linux、Linux-Windows tcp通信

    文章目录 前言 一.Linux - Linux 服务器 server 客户端 client 通信实操 二.socket编程在windows和linux下的区别 三.Windows - Linux 四. ...

  8. SOCKET编程-时间服务器和客户端的实现

    文章目录 UNIX_NET 获取服务器时间 connect函数 获取时间客户端程序实现 获取时间服务器实现 小技巧 宏定义的使用&&变参函数的宏定义实现 源码地址 UNIX_NET 获 ...

  9. python实现邮件客户端_python socket实现web服务器,邮件客户端

    本博客是针对,<计算机网络自顶向下方法>一书第二章后面套接字编程作业, 所有代码均已上传至我的github:https://github.com/inspurer/ComputerNetw ...

最新文章

  1. 刚发现的 Wi-Fi 安全漏洞,可能危及全球所有设备!
  2. 循环遍历Java字符串字符的规范方法——类似python for ch in string
  3. mybatis中$和#的区别
  4. 华为手机asph啥机型_华为正式宣布!19款机型开启新系统内测,你的手机榜首有名吗?...
  5. 三层架构——配置文件
  6. c语言记录五个数组编程,C语言经典编程之数组
  7. c,c++中字符串处理函数strtok,strstr,strchr,strsub
  8. UNIX网络编程笔记(6):I/O复用之select函数
  9. angular安装记录
  10. Android Junit测试
  11. Django 前后端数据传输、ajax、分页器
  12. React Native之APK文件签名及打包
  13. MatConvNet中关于vl_simplenn_display的一些分析
  14. asp毕业设计——基于asp+access的工资管理系统设计与实现(毕业论文+程序源码)——工资管理系统
  15. 微信小程序 上传头像截图功能
  16. jar构建docker镜像_将jar包打包为docker镜像
  17. 毕设 疲劳驾驶检测系统 python
  18. Pytest如何查找用例耗时最长的N个
  19. 记录学习java 所用的一些工具
  20. android 集成分享!!

热门文章

  1. 数据挖掘:大数据发展的核心驱动力
  2. JavaScript indexOf() 方法
  3. MySQL sql_model问题研究
  4. wemall app商城源码Android之支付宝接口公用函数
  5. 十四个方法提高博客的页面访问量
  6. 看我出招之:svchost.exe文件删不得
  7. 面试:Zookeeper
  8. Vue Router的详细教程
  9. Spring JSF集成
  10. 在 ASP.NET Core 5.0 中访问 HttpContext