目录
参考:
https://www.debugease.com/csharp/1114414.html
一、简介
1.1、提出问题
服务端明明监听到一个服务端,但是却没有连接成功,如下所示:
服务端的监听源码:
using KeenRay.Common;
using KeenRay.Common.SocketCommu;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Threading;
using System.Xml.Linq;
namespace KeenRay.SocketCommu
{
public class SocketCommuInit : BindableBase
{
#region 属性集
//服务端
public Socket Client
{
get;
set;
}
public int _receiveFlagValue = 0;
/// <summary>
/// 接收标志值
/// </summary>
public int ReceiveFlagValue
{
get { return _receiveFlagValue; }
set { SetProperty(ref _receiveFlagValue, value); }
}
#endregion
#region 字段集
SocketCommuReceive socketCommuReceive = new SocketCommuReceive();
//服务器
Socket Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//监听多个Client
Dictionary<string, Socket> clientList = new Dictionary<string, Socket>();
//IP
string strSocketIP = null;
//端口号
int point = 40000;
#endregion
#region 方法集
#region 单例
private volatile static SocketCommuInit _instance = null;
private static readonly object lockobj = new object();
/// <summary>
/// 创建实例
/// </summary>
/// <returns></returns>
public static SocketCommuInit CreateInstance()
{
if (_instance == null)
{
lock (lockobj)
{
if (_instance == null)
{
_instance = new SocketCommuInit();
}
}
}
return _instance;
}
#endregion
#region IP配置
/// <summary>
/// IP、端口配置
/// </summary>
public void IPandPortConfig()
{
try
{
string strSocketConfigFilePath;
strSocketConfigFilePath = Environment.CurrentDirectory + "\\Config" + "\\SocketAndBullHeadConfig.xml";
XDocument SocketDocument = XDocument.Load(strSocketConfigFilePath);
XElement SocketRoot = SocketDocument.Root;
//Socket节点
XElement SocketPoint = SocketRoot.Element("Socket");
//IP
XElement SocketIP = SocketPoint.Element("SocketIP");
strSocketIP = SocketIP.Value;
//端口
XElement SocketPort = SocketPoint.Element("SocketPort");
point = Convert.ToInt32(SocketPort.Value);
}
catch(Exception ex)
{
LogHelper.Error("SocketClass.cs::IPandPortConfig() IP/端口配置发生错误:--------------" + ex.ToString());
}
}
#endregion
#region 启动Socket
/// <summary>
/// 启动
/// </summary>
public void StartFlag()
{
//启动Socket
string strSocketStartFlag = null;
string strSocketConfigFilePath;
strSocketConfigFilePath = Environment.CurrentDirectory + "\\Config" + "\\SocketAndBullHeadConfig.xml";
XDocument SocketDocument = XDocument.Load(strSocketConfigFilePath);
XElement SocketRoot = SocketDocument.Root;
//Socket节点
XElement SocketPoint = SocketRoot.Element("Socket");
//启动Socket
XElement SocketStart = SocketPoint.Element("SocketStart");
strSocketStartFlag = SocketStart.Value;
if (strSocketStartFlag == "1")
{
IPAddress IP = IPAddress.Parse(strSocketIP);
IPEndPoint iPEndPoint = new IPEndPoint(IP, point);
Server.Bind(iPEndPoint);
Server.Listen(10);
//开启线程监听
Thread th = new Thread(ListenFunc);
th.IsBackground = true;
th.Start(Server);
}
}
#endregion
#region 监听
/// <summary>
/// 监听
/// </summary>
/// <param name="objListen"></param>
public void ListenFunc(object Server)
{
while (true)
{
try
{
//客户端
Client = ((Socket)Server).Accept();
//clientList.Add(Client.RemoteEndPoint.ToString(), Client); //可以监听多个Client
Thread threadServer = new Thread(new ParameterizedThreadStart(socketCommuReceive.Receive));
threadServer.IsBackground = true;
threadServer.Start(Client);
}
catch (Exception ex)
{
LogHelper.Error("SocketClass.cs::Listen()监听发错了错误:--------------" + ex.ToString());
}
}
}
#endregion
#endregion
}
}
客户端的连接源码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Win32;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Threading;
using KeenRayLargePC.Views;
using System.Windows.Interop;
using System.Xml.Linq;
using System.Drawing.Imaging;
using System.Drawing;
using KeenRayLargePC.Common;
using KeenRayLargePC.Config;
using System.ComponentModel;
using System.Windows.Forms.Integration;
using AxKrayImgViewLib;
using KeenRayLargePC.DicomOperate;
using Prism.Commands;
using KeenRayLargePC.PadDataAcessLayer;
using KeenRayLargePC.PadDbContent;
using System.Linq.Expressions;
using KeenRayLargePC.Server;
namespace KeenRayLargePC
{
public partial class MainWindow : Window,INotifyPropertyChanged
{
#region 命令集
/// <summary>
/// 窗宽改变命令
/// </summary>
public DelegateCommand SliderWWValueChangedCommand { get; private set; }
/// <summary>
/// 窗位改变命令
/// </summary>
public DelegateCommand SliderWLValueChangedCommand { get; private set; }
#endregion
#region 属性集
BitmapImage bmpImage = null;
public BitmapImage BmpImage
{
get
{
return bmpImage;
}
set
{
bmpImage = value;
RaiseChanged("VideoImage");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(property));
}
}
private int _winWidth = 1;
/// <summary>
/// 窗宽
/// </summary>
public int WinWidth
{
get { return _winWidth; }
set
{
_winWidth = value;
if (PropertyChanged != null)
{
//RaisePropertyChanged("PopupEraserMoreIsOpen");
PropertyChanged(this, new PropertyChangedEventArgs("WinWidth"));
}
}
}
private int _winLevel = 1;
/// <summary>
/// 窗位
/// </summary>
public int WinLevel
{
get { return _winLevel; }
set
{
_winLevel = value;
if (PropertyChanged != null)
{
//RaisePropertyChanged("PopupEraserMoreIsOpen");
PropertyChanged(this, new PropertyChangedEventArgs("WinLevel"));
}
}
}
private bool _popupEraserMoreIsOpen;
/// <summary>
/// 清除菜单是否打开
/// </summary>
public bool PopupEraserMoreIsOpen
{
get { return _popupEraserMoreIsOpen; }
set
{
_popupEraserMoreIsOpen = value;
if (PropertyChanged != null)
{
//RaisePropertyChanged("PopupEraserMoreIsOpen");
PropertyChanged(this, new PropertyChangedEventArgs("PopupEraserMoreIsOpen"));
}
}
}
#endregion
#region 标志集
/*页面标志*/
const int HOMEPAGE_FLAG = 1;
const int STUDYPAGE_FLAG = 2;
const int REVIEWPAGE_FLAG = 3;
/*曝光参数标志*/
const int KV_PLUS_FLAG = 11;
const int KV_REDUCE_FLAG = 12;
const int MA_PLUS_FLAG = 13;
const int MA_REDUCE_FLAG = 14;
const int MS_PLUS_FLAG = 15;
const int MS_REDUCE_FLAG = 16;
const int MAS_PLUS_FLAG = 17;
const int MAS_REDUCE_FLAG = 18;
const int MAS_MODE_FLAG = 19;
const int MAMS_MODE_FLAG = 20;
const int FOCUS_FLAG = 21;
const int START_EXPOSE_FLAG = 22;//启动曝光按钮
const int SAVE_EXPOSE_VALUE = 23;//保存曝光参数
/*导航状态标志*/
const int OPEN_VIDEO_FLAG = 31;//打开视频监控
const int CLOSE_VIDEO_FLAG = 32;//关闭视屏监控
const int PANEL_TEMP_FLAG = 33; //平板温度
const int HEAT_CAPACITY_FLAG = 34;//热容量
const int BATTERY_CAPACITY_FLAG = 35;//电池容量
const int EXPOSE_STATUS_FLAG = 36;//曝光状态。接收到的内容(int),0:就绪。1:预备。2:曝光。3:禁止。
/*其他信息标志*/
const int DICOM_FLAG = 41; //Dicom
const int USER_INFO_FLAG = 42; //用户信息
/*状态标志*/
bool blStartFlag = false; //Socket启动标志
bool imageEditFlag = false; //图像编辑标识
bool blCameraRecStatue = false; //视频监控开关状态。false:关闭。true:打开。
bool blImageRecStatue = false;
bool blCommonRecStatue = false; //其他状态开关标志
const string strCameraRecStatue = "CameraRecStatue";
const string strImageRecStatue = "ImageRecStatue";
const string strCommonRecStatue = "CommonRecStatue";
bool blUpdateTimeFlag = true; //是否运行实时更新时间
bool blCanAnalysisPackageHead = true; //是否允许解析包头
bool blCanAnalysisPackageContent = true; //是否允许解析包内容
#endregion
#region 属性集
#region 图像显示控件属性
public bool m_bEditFlag = false; //编辑标志
public int m_nGrabAcqStatus; //0-DR 1-RF 2-SPOT
public int nWindowLevel; //窗位
public int nWindowWidth; //窗宽
public KrayDicomLib.DicomFile m_cDicomFile;
ImgViewHandle handle = new ImgViewHandle();
#endregion
#region 包属性:用来解析包,实现被动接收,如接收Dicom,用户信息
byte[] bytPageType = new byte[4]; //页面类型
byte[] bytRecFlag = new byte[4]; //标志位字节
byte[] bytContentLong = new byte[4]; //长度字节
byte[] bytContent = new byte[0]; //内容
int iPageFlag = -1; //页面类型
int iRecFlag = -1; //接收标志
int iContentLong = -1; //包内容长度
int iPathLong = -1; //Dicom图路径长度
const int FLAG_LENGTH = 12; //包头长度
#endregion
#region Dicom图操作
PatientInfoDal patientInfoDal = new PatientInfoDal();
SeriesInfoDal seriesInfoDal = new SeriesInfoDal();
ImagesInfoDal imagesInfoDal = new ImagesInfoDal();
List<PatientInfo> patientInfoList = new List<PatientInfo>();
List<SeriesInfo> seriesInfoList = new List<SeriesInfo>();
List<ImagesInfo> imagesInfoList = new List<ImagesInfo>();
#endregion
#region 视频监控属性
List<byte> VideoList = new List<byte>(); //存放视频帧
const int BITMAP_IMAGE_LENGTH = 921654; //帧字节长度
byte[] btCurrentBitmapImage = new byte[BITMAP_IMAGE_LENGTH];//当前帧
byte[] btLastBitmapImage = new byte[BITMAP_IMAGE_LENGTH]; //上一帧
#endregion
#region Socket通用属性
List<byte> bufferList = new List<byte>(); //缓存队列
byte[] btRecBuffer = new byte[16* 1000 * 1000];//socket接收缓存区
int Port = 50000;//端口号
IPAddress IP = IPAddress.Parse("127.0.0.1");
IpConfig ipConfig = new IpConfig();
IPEndPoint serverIPEndPoint = null;
public Socket Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Log log = Log.CreateInstance();//日志类
iPadReceive ipadReceive = iPadReceive.CreateInstance();
iPadSend ipadSend = iPadSend.CreateInstance();
InitPacs initPacs = InitPacs.CreateInstance();//启动Pacs初始配置。
SendModality sendModality = SendModality.CreateInstance();
#endregion
#endregion
#region 方法集
#region 单例
//public volatile static MainWindow _instance = null;
//public static readonly object lockobj = new object();
/ <summary>
/ 创建实例
/ </summary>
/ <returns></returns>
//public static MainWindow CreateInstance()
//{
// if (_instance == null)
// {
// lock (lockobj)
// {
// if (_instance == null)
// {
// _instance = this;
// }
// }
// }
// return _instance;
//}
#endregion
/// <summary>
/// 默认构造函数
/// </summary>
public MainWindow()
{
//InitializeComponent();
log.ClearLogFunc();//清除日志
ipadReceive.setMainWindowDeleaget(this);
ipadSend.setMainWindowDeleaget(this);
//更新UI: 可以用
App.Current.Dispatcher.Invoke((Action)delegate ()
{
this.DataContext = this;
});
//窗宽改变命令初始化
SliderWWValueChangedCommand = new DelegateCommand(SliderWWValueChangedFun);
//窗位改变命令初始化
SliderWLValueChangedCommand = new DelegateCommand(SliderWLValueChangedFun);
m_nGrabAcqStatus = 0;
nWindowWidth = 65535;
nWindowLevel = 32768;
//获取配置文件默认的IP、Port
ipConfig.IpConfigFunc(ref blStartFlag, ref IP, ref Port);
StartFunc();//默认就启动Socket连接PC
/* 线程更新时间 */
Thread UpdateTimeThread = new Thread(UpdateTime);
UpdateTimeThread.IsBackground = true;
UpdateTimeThread.Start();
}
/// <summary>
/// 启动
/// </summary>
private void StartFunc()
{
try
{
if (blStartFlag == true)
{
serverIPEndPoint = new IPEndPoint(IP, Port);
//获得要连接的远程服务器应用程序的IP地址和端口号
Client.Connect(serverIPEndPoint);
if (Client.Connected == true)
{
log.WriteDebugLogFunc("MainWindow.xaml.cs::StartFunc()——" + "已连接服务器" + "\n\n");
MessageBox.Show("连接服务器状态:成功");
/*开线程接收*/
Thread threadReceive = new Thread(ipadReceive.Receive);
threadReceive.IsBackground = true;
threadReceive.Start(Client);
/*开线程发送归档状态信息*/
Thread thSendModality = new Thread(sendModality.SendImageArchiveFunc2);
thSendModality.IsBackground = true;
thSendModality.Start();
}
else
{
log.WriteDebugLogFunc("MainWindow.xaml.cs::StartFunc()——" + "服务器已经开启,但无法连接服务器" + "\n\n");
}
}
}
catch (Exception ex)
{
//MessageBox.Show("服务器未开启或客户端输入的IP不正确");
log.WriteErrorLogFunc("MainWindow.xaml.cs::StartFunc()——" + "服务器未开启或客户端输入的IP不正确:" + ex.ToString() + "\n\n");
}
}
/// <summary>
/// 导图:iPads导图到Pacs
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_SendPacs_Click(object sender, RoutedEventArgs e)
{
try
{
Pacs pacsDialog = new Pacs();
pacsDialog.SetValidServerList();
pacsDialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
pacsDialog.ShowDialog();
}
catch (Exception ex)
{
log.WriteErrorLogFunc("MainWindow.xaml.cs::btn_Image_Click()——" + "视频监控开关状态发送错误:" + ex.ToString() + "\n\n");
}
}
/// <summary>
/// 关闭系统
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnSysShutDown_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
/// <summary>
/// 系统配置,弹窗window窗口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSystemConfig_Click(object sender, RoutedEventArgs e)
{
try
{
if (Client != null && Client.Connected == true)
{
MessageBox.Show("Pad已经连上PC,无需配置IP/Port了");
return;
}
SystemConfigWindow systemConfigWindow = new SystemConfigWindow();
systemConfigWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
if (systemConfigWindow.ShowDialog() == true)
{
IP = IPAddress.Parse(systemConfigWindow.IP);
Port = systemConfigWindow.Port;
blStartFlag = true;//若是IP配置正确,则启动Socket连接
}
StartFunc();//启动Socket连接
}
catch(Exception ex)
{
log.WriteErrorLogFunc("MainWindow.xaml.cs::btnSystemConfig_Click()——" + "IP格式或端口不正确:" + ex.ToString() + "\n\n");
}
}
#region 更新时间
/// <summary>
/// 更新时间
/// </summary>
private void UpdateTime()
{
while (blUpdateTimeFlag == true)
{
Thread.Sleep(1000);
//更新UI: 可以用
App.Current.Dispatcher.Invoke((Action)delegate ()
{
this.lblDateTime_Second.Content = DateTime.Now.ToLongTimeString().ToString();
this.lblDateTime_day.Content = DateTime.Now.ToString("yyyy-MM-dd");
});
}
}
#endregion
#region 发送视频监控
/// <summary>
/// 视频监控开关状态
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Camera_Click(object sender, RoutedEventArgs e)
{
try
{
if (blCameraRecStatue == false)//如果在关闭状态下,那就打开它。
{
//视频打开,其他功能必须关闭
ModuleRunFlagFunc(strCameraRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, OPEN_VIDEO_FLAG, null);
}
else if (blCameraRecStatue == true)// 如果在打开状态下,那就关闭它。
{
blCameraRecStatue = false;
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, CLOSE_VIDEO_FLAG, null);
//关闭视频监控下,必须清空Image的画面
App.Current.Dispatcher.Invoke((Action)delegate ()
{
imgDisPlay.Source = null;
});
}
}
catch (Exception ex)
{
log.WriteErrorLogFunc("MainWindow.xaml.cs::Camera_Click()——" + "视频监控开关状态发送错误:" + ex.ToString() + "\n\n");
}
}
#endregion
#region 发送曝光标志
/// <summary>
/// 启动曝光
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnExpose_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, START_EXPOSE_FLAG, null);
}
private void btn_KvPlus_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, KV_PLUS_FLAG, null);
}
private void btn_KvReduce_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, KV_REDUCE_FLAG, null);
}
private void btn_mAPlus_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, MA_PLUS_FLAG, null);
}
private void btn_mAReduce_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, MA_REDUCE_FLAG, null);
}
private void btn_msPlus_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, MS_PLUS_FLAG, null);
}
private void btn_msReduce_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, MS_REDUCE_FLAG, null);
}
private void btn_mAsPlus_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, MAS_PLUS_FLAG, null);
}
private void btn_mAsReduce_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, MAS_REDUCE_FLAG, null);
}
private void btn_mAsMode_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, MAS_MODE_FLAG, null);
}
private void btn_mAmsMode_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, MAMS_MODE_FLAG, null);
}
/// <summary>
/// 焦点
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_Focus_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, FOCUS_FLAG, null);
}
private void btn_SaveExposeValues_Click(object sender, RoutedEventArgs e)
{
//其他功能必须关闭
ModuleRunFlagFunc(strCommonRecStatue);
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, SAVE_EXPOSE_VALUE, null);
}
#endregion
/// <summary>
/// 模块运行标志
/// </summary>
/// <param name="str"></param>
public void ModuleRunFlagFunc(string str)
{
switch (str)
{
case strCameraRecStatue:
blCameraRecStatue = true;
blImageRecStatue = false;
blCommonRecStatue = false;
break;
case strImageRecStatue:
blCameraRecStatue = false;
blImageRecStatue = true;
blCommonRecStatue = false;
//同时需要发一个信息给主程序,关闭视频监控,不让它发信息过来了。
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, CLOSE_VIDEO_FLAG, null);
//并且让当前的image清零
App.Current.Dispatcher.Invoke((Action)delegate ()
{
this.imgDisPlay.Source = null;
});
break;
case strCommonRecStatue:
//同时需要发一个信息给主程序,关闭视频监控,不让它发信息过来了。
ipadSend.SendPackageFunc(STUDYPAGE_FLAG, CLOSE_VIDEO_FLAG, null);
//并且让当前的image清零
App.Current.Dispatcher.Invoke((Action)delegate ()
{
this.imgDisPlay.Source = null;
});
blCameraRecStatue = false;
blImageRecStatue = false;
blCommonRecStatue = true;
break;
default:
break;
}
}
#region Dicom图
/// <summary>
/// 点击加载一张Dicom图:主要用来测试
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OpenDicom_Click(object sender, RoutedEventArgs e)
{
try
{ /*直接打开*/
//System.Windows.Forms.OpenFileDialog open = new System.Windows.Forms.OpenFileDialog();
//open.Filter = "DCM图像文件|*.dcm";
//open.RestoreDirectory = false;
//if (open.ShowDialog() == System.Windows.Forms.DialogResult.OK)
//{
// handle.PutImage(this.imageview, open.FileName, ref m_cDicomFile);
//}
适应窗口
//imageview.FtsImage();
//this.imageview.Invalidate();
隐藏视频监控窗口
//this.imgDisPlay.Visibility = Visibility.Hidden;
//this.host.Visibility = Visibility.Visible;
/*调用ShowDicom打开*/
System.Windows.Forms.OpenFileDialog open = new System.Windows.Forms.OpenFileDialog();
open.Filter = "DCM图像文件|*.dcm";
open.RestoreDirectory = false;
if (open.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
ipadReceive.ShowDicom(open.FileName);
}
}
catch (Exception ex)
{
log.WriteErrorLogFunc("MainWindow.xaml.cs::OpenDicom_Click()——" + "打开dicom图发生错误:" + ex.ToString() + "\n\n");
}
}
/// <summary>
/// 左旋转
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_LeftRotate_Click(object sender, RoutedEventArgs e)
{
this.imageview.LeftRotate();
this.imageview.Invalidate();
}
/// <summary>
/// 右旋转
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_RightRotate_Click(object sender, RoutedEventArgs e)
{
this.imageview.RightRotate();
this.imageview.Invalidate();
}
/// <summary>
/// 下侧翻
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_DownFlip_Click(object sender, RoutedEventArgs e)
{
this.imageview.FlipVertical();
this.imageview.Invalidate();
}
/// <summary>
/// 右侧翻
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_RightFlip_Click(object sender, RoutedEventArgs e)
{
this.imageview.FlipHorizon();
this.imageview.Invalidate();
}
/// <summary>
/// 等比显示:显示一张图
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_ShowOneImage_Click(object sender, RoutedEventArgs e)
{
if (this.imageview.HasImage)
{
this.imageview.RealSizeImage();
this.imageview.Invalidate();
}
}
/// <summary>
/// 全屏显示
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_FullScreen_Click(object sender, RoutedEventArgs e)
{
//适应窗口
imageview.FtsImage();
imageview.Invalidate();
}
/// <summary>
/// 手抓移动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_AllowMove_Click(object sender, RoutedEventArgs e)
{
if (this.imageview.HasImage)
{
this.imageview.ProcType = KrayImgViewLib.tagPROC_TYPE.PT_MOVE;
}
}
/// <summary>
/// 禁止移动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_ForbiddenMove_Click(object sender, RoutedEventArgs e)
{
if (this.imageview.HasImage)
{
this.imageview.ProcType = KrayImgViewLib.tagPROC_TYPE.PT_NONE;
this.imageview.Invalidate();
}
}
/// <summary>
/// 右标记
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnR_Click(object sender, RoutedEventArgs e)
{
//string sFontName = configInfoModel.RLMarkFontName;
//int nFontSize = configInfoModel.RLMarkFontSize;
string sFontName = "微软雅黑";
int nFontSize = 200;
if (this.imageview.HasImage)
{
this.imageview.DrawFlag = "R";
this.imageview.AddText(200, 30, "R", nFontSize, sFontName);
this.imageview.ProcType = KrayImgViewLib.tagPROC_TYPE.PT_NONE;
this.imageview.Invalidate();
SetEditFlag(true);
}
}
/// <summary>
/// 设置编辑标志值
/// </summary>
/// <param name="state"></param>
public void SetEditFlag(bool state)
{
imageEditFlag = state;
}
/// <summary>
/// 左标识命令功能函数
/// </summary>
private void btnL_Click(object sender, RoutedEventArgs e)
{
//string sFontName = configInfoModel.RLMarkFontName;
//int nFontSize = configInfoModel.RLMarkFontSize;
string sFontName = "微软雅黑";
int nFontSize = 200;
if (this.imageview.HasImage)
{
int X2 = this.imageview.Width - 200;
int Y2 = 30;
this.imageview.DrawFlag = "L";
this.imageview.AddText(X2, Y2, "L", nFontSize, sFontName);
this.imageview.ProcType = KrayImgViewLib.tagPROC_TYPE.PT_NONE;
this.imageview.Invalidate();
SetEditFlag(true);
}
}
/// <summary>
/// 文字标识命令功能函数
/// </summary>
private void btnText_Click(object sender, RoutedEventArgs e)
{
string sFontName = "微软雅黑";
int nFontSize = 80;
if (this.imageview.HasImage)
{
this.imageview.SetTextFont(sFontName, nFontSize);
this.imageview.ProcType = KrayImgViewLib.tagPROC_TYPE.PT_TEXT;
SetEditFlag(true);
}
}
/// <summary>
/// 清除更多命令功能函数
/// </summary>
private void btnClearMore_Click(object sender, RoutedEventArgs e)
{
PopupEraserMoreIsOpen = true;
//PopupEraserMoreIsOpen = true;
}
/// <summary>
/// 清除所有命令功能函数
/// </summary>
private void btnClearAll_Click(object sender, RoutedEventArgs e)
{
if (this.imageview.HasImage)
{
this.imageview.DeleteAnnotation(true);
this.imageview.Invalidate();
SetEditFlag(true);
}
PopupEraserMoreIsOpen = false;
}
/// <summary>
/// 清除所选命令功能函数
/// </summary>
private void btnClearChoose_Click(object sender, RoutedEventArgs e)
{
if (this.imageview.HasImage)
{
this.imageview.DeleteAnnotation(false);
this.imageview.Invalidate();
SetEditFlag(true);
}
PopupEraserMoreIsOpen = false;
}
/// <summary>
/// 反白
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnInvert_Click(object sender, RoutedEventArgs e)
{
if (this.imageview.HasImage)
{
this.imageview.BlackWhite();
this.imageview.Invalidate();
SetEditFlag(true);
}
}
/// <summary>
/// 自动窗宽窗位
/// </summary>
private void btnAutoWL_Click(object sender, RoutedEventArgs e)
{
int winWidth = WinWidth; //窗宽
int winLevel = WinLevel; //窗位
if (this.imageview.HasImage)
{
this.imageview.SetOptimizeWindowLevel();
this.imageview.GetWindowLevel(out winWidth, out winLevel);
WinWidth = winWidth;
WinLevel = winLevel;
//UpdateWWWLSlider();
SetEditFlag(true);
}
}
/// <summary>
/// 窗宽改变命令初始化功能函数
/// </summary>
private void SliderWWValueChangedFun()
{
if (this.imageview != null)
{
if (this.imageview.HasImage)
{
WinWidth = (int)this.SliderWW.Value;
RefreshWWWLImageView();
}
}
}
/// <summary>
/// 窗位改变命令初始化功能函数
/// </summary>
private void SliderWLValueChangedFun()
{
if (this.imageview != null)
{
if (this.imageview.HasImage)
{
WinLevel = (int)this.SliderWL.Value;
RefreshWWWLImageView();
}
}
}
/// <summary>
/// 窗宽窗位控件值与直方图更新显示功能函数
/// </summary>
private void RefreshWWWLImageView()
{
//判断是否有图像,当前绘画非病人信息(后面增加)
if (this.imageview.HasImage)
{
this.imageview.SetWindowLevel(WinWidth, WinLevel);
this.imageview.Invalidate();
}
}
/// <summary>
/// 保存图像单击功能函数
/// </summary>
private void btnSaveImage_Click(object sender, RoutedEventArgs e)
{
string msg = "保存图像";
SaveImageFun(msg);
}
/// <summary>
/// 保存图像函数
/// </summary>
private void SaveImageFun(string msg)
{
int imgHeight = 0; //图像高
int imgWidth = 0; //图像宽
int imgBit = 0; //图像位
int imgSize = 0; //图像大小
/*图像显示控件无图像,则返回*/
if (!this.imageview.HasImage)
{
//EMessageBox.Show("未选择图像或显示控件无图像!", "提示", EMessageBoxButton.OK, EMessageBoxImage.Information);
System.Windows.MessageBox.Show("显示控件无图像");
SetEditFlag(false);
return;
}
}
#endregion
#endregion
}
}
1.2、问题分析
仔细考虑了一下上下文,对比了https://blog.csdn.net/xpj8888/article/details/83536880,并单部执行了,发现了是参数类型的问题。Receive(Object obj)应该替换为Receive(object obj),就不会出错了。
Object是类,而object是类型。具体的区别,可以参考https://docs.microsoft.com/en-us/dotnet/api/system.object?redirectedfrom=MSDN&view=netframework-4.8
1.3、拓展Socket的同步连接与异步连接
针对1.1问题,我当时考虑、并调试了好久,好在终于发现问题。我一度地怀疑Socket同步与异步的问题。我是一个不言放弃、勇于探索的人。好了,现在花点时间,来学习Socket同步与异步。学习,就要举一反三。
1.3.1、什么是同步连接、异步连接
http://blog.sina.com.cn/s/blog_5d29ee450102vrfg.html
同步连接:
比如1.1就是一个同步通信方式,它的工作方式与阻塞优点类似。即,每个服务对象,都要开启一个线程,浪费线程资源,性能差,可接入用户数量少。(但要注意同步通信与阻塞通信不是等同的)
异步连接:参考https://www.debugease.com/csharp/1114414.html
- 可接入用户较多、性能高
- 一般用异步socket大概可以支持1000个客户端,如果需要更多的话,建议用完成端口(IOCP)。
- 被人做过异步的通讯项目,在1500个客户端连接时,服务器端只有50个左右的线程......相当完美。
- 对于异步Socket,连接数与线程数关系不大,与内存占用才是线性关系。https://bbs.csdn.net/topics/390510655?page=1
二、Socket同步通信实现
同步实现,请参考1.1。或者参考下面的完整代码:
2.1、Server
MainWindow.xaml
<Window x:Class="Server.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Server"
mc:Ignorable="d"
Title="Server" Height="450" Width="850">
<Grid Height="400" Width="800">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="6*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Canvas Grid.Row="0" Background="#FF00FFC0" >
<Label Content="Server IP" Canvas.Left="19" Canvas.Top="14"/>
<Label Content="Server Port" Canvas.Left="221" Canvas.Top="14"/>
<Label Content="Clients IPs/Ports" Canvas.Left="397" Canvas.Top="15"/>
<TextBox x:Name="txtPort" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="50000" VerticalAlignment="Top" Width="82" Canvas.Left="297" Canvas.Top="15"/>
<TextBox x:Name="txtIP" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="127.0.0.1" VerticalAlignment="Top" Width="107" Canvas.Left="86" Canvas.Top="15"/>
<!--<ComboBox x:Name="cboUsers" HorizontalAlignment="Left" VerticalAlignment="Top" Width="150" Height="23" Canvas.Left="505" Canvas.Top="15">
</ComboBox>-->
</Canvas>
<Canvas Grid.Row="1" Background="#FFD3E5C2" >
<TextBox x:Name="txtContent" HorizontalAlignment="Left" Height="185" TextWrapping="Wrap" VerticalAlignment="Top" Width="375" Canvas.Left="26" Canvas.Top="9"/>
<Label Content="消息记录" Canvas.Left="337" Canvas.Top="13" Background="#FFDFC5C5"/>
<TextBox x:Name="txtSendMsg" HorizontalAlignment="Left" Height="87" TextWrapping="Wrap" VerticalAlignment="Top" Width="376" Canvas.Top="205" Canvas.Left="26"/>
<Label Content="编辑消息" Canvas.Left="339" Canvas.Top="209" Background="#FFDFC5C5" RenderTransformOrigin="0.741,7.92"/>
<Border BorderBrush="#FF39222B" BorderThickness="2" Height="300" Width="342" Canvas.Left="448" Canvas.Top="-2"/>
<Border BorderBrush="#FF39222B" BorderThickness="2" Height="43" Width="342" Canvas.Left="448" Canvas.Bottom="0" Canvas.Top="255" Background="#FF7B7BDF"/>
<Image x:Name="Image_PlayImage" Height="250" Width="326" Canvas.Left="455" Canvas.Top="3"/>
</Canvas>
<Canvas Grid.Row="2" Background="#FF00FFC0" >
<Button x:Name="btnSendMsg" Content="发送消息" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76" Click="btnSendMsg_Click" Canvas.Left="141" Canvas.Top="19"/>
<!--<Button x:Name="btnShock" Content="震动" HorizontalAlignment="Left" VerticalAlignment="Top" Width="57" Click="btnShock_Click" Canvas.Left="266" Canvas.Top="19"/>-->
<Button x:Name="btnSendFile" Content="发送文件" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="btnSendFile_Click" Canvas.Left="629" Canvas.Top="19"/>
<Button x:Name="btnChooseFile" Content=" 选择文件" HorizontalAlignment="Left" VerticalAlignment="Top" Width="55" Click="btnChooseFile_Click" Canvas.Left="528" Canvas.Top="19"/>
<TextBox x:Name="txtFilePath" HorizontalAlignment="Left" Height="27" TextWrapping="Wrap" VerticalAlignment="Top" Width="330" Canvas.Left="455" Canvas.Top="-36"/>
<Button x:Name="BtnSysShutDown" Content="退出" BorderThickness="2" Click="BtnSysShutDown_Click" Height="41" Width="71" Background="#FFA31D77" Canvas.Left="2" Canvas.Top="4" ></Button>
</Canvas>
</Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.Win32;
using System;
using System.Collections.Generic;
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;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace Server
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
string Receive_IPandPort = "";
public MainWindow()
{
InitializeComponent();
//当点击开始监听的时候,在服务器端创建一个负责监听IP地址跟端口号的Socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse("127.0.0.1");//IPAddress.Any;
//创建端口号对象
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
//监听
socketWatch.Bind(point);
ShowMsg("监听成功");
socketWatch.Listen(10);
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
}
public delegate void delegate1(string str);//定义委托
public delegate int delegate2(string endPoint);
Socket Server;
//将远程连接的客户端的IP地址和Socket存入集合中
Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
/// <summary>
/// 等待客户端的连接,并且创建与之通信的Socket
/// </summary>
/// <param name="o"></param>
void Listen(object o)
{
Socket socketWatch = o as Socket;
//等待客户端的连接,并且创建一个负责通信的Socket
while (true)
{
try
{
//负责跟客户端通信的Socket
Server = socketWatch.Accept();
//将远程连接的客户端的IP地址和Socket存入集合中
dicSocket.Add(Server.RemoteEndPoint.ToString(), Server);
//将远程连接的客户端的IP地址和端口号存储下拉框中
//cboUsers.Items.Add(Server.RemoteEndPoint.ToString());
//Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate2(cboUsers.Items.Add), Server.RemoteEndPoint.ToString());
Receive_IPandPort = Server.RemoteEndPoint.ToString();
//192.168.0.100:连接成功
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), Server.RemoteEndPoint.ToString() + ":" + "连接成功");
//开启一个新的线程,不停地接收客户端发送过来的消息
Thread th = new Thread(Receive);
th.IsBackground = true;
th.Start(Server);
}
catch { }
}
}
/// <summary>
/// 服务端不停地接收客户端发送过来的消息
/// </summary>
/// <param name="o"></param>
void Receive(object o)
{
Socket Server = o as Socket;
while (true)
{
try
{
//客户端连接成功后,服务器应该接收服务器应该接收客户端发来的消息
byte[] buffer = new byte[1024 * 1024 * 2];
//实际接收到的有效字节数
int r = Server.Receive(buffer);
if (r == 0)
{
break;
}
else if (buffer[0] == 0)
{
string str = Encoding.UTF8.GetString(buffer, 1, r-1);
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), "[接收]" + Server.RemoteEndPoint.ToString() + ":" + str);
}
else if (buffer[0] == 1)
{
string savePath;
byte[] fileContext = new byte[0];
GetSavePathAndFileContextByte(buffer, out savePath, out fileContext); //读取从客户端传输过来的文件名、文件内容
System.IO.File.WriteAllBytes(savePath, fileContext);//将内容写入到制定的路径。
//MessageBox.Show("保存图片成功");
ShowImage(savePath);
string fileName = System.IO.Path.GetFileName(savePath);
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), "[接收]" + Server.RemoteEndPoint.ToString() + ":" + "接收的图片或文件:" + fileName);
}
else if (buffer[0] == 2)
{
//Shock();
}
}
catch
{
//MessageBox.Show("你接收的是非法文件或非法消息");
}
}
}
private void ShowMsg(string str)
{
txtContent.AppendText(str + "\r\n");
}
private void ShowImage(string path)
{
this.Dispatcher.BeginInvoke((Action)delegate ()//异步委托,直接更新UI线程
{
//string fileName = System.IO.Path.GetFileName(path);
//Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), "[接收]" + Client.RemoteEndPoint.ToString() + ":" + "接收的图片或文件:" + fileName);
string ReceiveFileNameProperty_str = System.IO.Path.GetExtension(path); //获取后缀。
//必须判断,是图片执行,并显示。
if ((ReceiveFileNameProperty_str == ".jpg")
|| (ReceiveFileNameProperty_str == ".png")
|| (ReceiveFileNameProperty_str == ".bmp")
|| (ReceiveFileNameProperty_str == ".jpeg")
|| (ReceiveFileNameProperty_str == ".JPG")
|| (ReceiveFileNameProperty_str == ".PNG")
|| (ReceiveFileNameProperty_str == ".BMP")
|| (ReceiveFileNameProperty_str == ".JPEG"))
{
Image_PlayImage.Source = new BitmapImage(new Uri(path, UriKind.Absolute));//绝对路径
}
//btn_StartServer.Content = "接收完成";
}
);
}
/// <summary>
/// 服务器给客户端发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSendMsg_Click(object sender, RoutedEventArgs e)
{
string str = txtSendMsg.Text.Trim();
byte[] buffer = Encoding.UTF8.GetBytes(str);
List<byte> list = new List<byte>();
list.Add(0);
list.AddRange(buffer);
//将泛型集合转换为数组
byte[] newBuffer = list.ToArray();
//获得用户在下拉框中选中的IP地址
//string ip = cboUsers.SelectedItem.ToString();
//dicSocket[ip].Send(newBuffer);
dicSocket[Receive_IPandPort].Send(newBuffer);
txtSendMsg.Text = "";
//发送时,也要在消息显示发送的消息。
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), "[发送]" + Server.RemoteEndPoint.ToString() + ":" + str);
}
/// <summary>
/// 选择要发送的文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnChooseFile_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.InitialDirectory = "C:\\Users\\Administrator\\Desktop\\Server发";
//ofd.Title = "请选择要发送的文件";
//ofd.Filter = "所有文件|*.*";
ofd.ShowDialog();
txtFilePath.Text = ofd.FileName;
ShowImage(txtFilePath.Text);
}
private void btnSendFile_Click(object sender, RoutedEventArgs e)
{
string path = txtFilePath.Text;//文件的路径
string fileName = System.IO.Path.GetFileName(path);
Byte[] fileNameByte = GetFileNameByte(fileName);//文件名的字节数。
Byte[] fileContentByte = GetfileContentByte(path);//文件内容。
Byte[] combomArray = GetCombomFileByte(fileNameByte, fileContentByte);//总发送的内容。
//dicSocket[cboUsers.SelectedItem.ToString()].Send(combomArray, 0, combomArray.Length, SocketFlags.None);
dicSocket[Receive_IPandPort].Send(combomArray, 0, combomArray.Length, SocketFlags.None);
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), "[发送]" + Server.RemoteEndPoint.ToString() + ":" + "已经发送图片或文件:" + fileName);
}
private Byte[] GetFileNameByte(string SendFileName_str)
{
byte[] fileNameByteVar = System.Text.Encoding.UTF8.GetBytes(SendFileName_str);
return fileNameByteVar;
}
private Byte[] GetfileContentByte(string path)
{
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);//读取文件
Byte[] fileContentByteVar = new Byte[fs.Length];
try
{
fs.Read(fileContentByteVar, 0, fileContentByteVar.Length);
fs.Close();
//return fileContentByteVar;
}
catch
{
MessageBox.Show("获取文件内容字节失败");
//return fileContentByteVar;
}
return fileContentByteVar;
}
/// <summary>
/// 四部分,第一部分为1B,区分发送类型,即指令或文件。二部分为4B,保存文件名所占的字符串长度。三部分,保存文件名的内容。四部分,文件的正式内容。
/// </summary>
/// <param name="fileNameByte"></param>
/// <param name="fileContentByte"></param>
/// <returns></returns>
private Byte[] GetCombomFileByte(Byte[] fileNameByte, Byte[] fileContentByte)
{
int fileNameLong = fileNameByte.Length;//将文件的长度保存为一个整数。
byte[] fileNameLongByte = new byte[4];//将整数放在4个字节中传输。
fileNameLongByte = BitConverter.GetBytes(fileNameLong);//一个int等于四个字节。
int combomFileLong = 1 + fileNameByte.Length + fileNameLongByte.Length + fileContentByte.Length;//总字节长度
Byte[] combomFileByteTemple = new byte[combomFileLong];
for (int i = 0; i < combomFileLong; i++)
{
if (i == 0)//区分发送类型,即指令或文件
{
combomFileByteTemple[0] = 1;// 1表示发送文件
}
else if ((i > 0) && (i < (fileNameLongByte.Length + 1)))//确认文件名的长度,四个字节保存。
{
combomFileByteTemple[i] = fileNameLongByte[i-1];
}
else if ( (i >= (fileNameLongByte.Length + 1)) && (i < (fileNameByte.Length + fileNameLongByte.Length + 1)) )//文件名的内容
{
combomFileByteTemple[i] = fileNameByte[i - fileNameLongByte.Length - 1];//从第0号位置读取fileNameByte
}
else
{
combomFileByteTemple[i] = fileContentByte[i - fileNameByte.Length - fileNameLongByte.Length - 1];//从第0号位置读取fileContentByte
}
}
return combomFileByteTemple;
}
/// <summary>
/// 获取文件路径path(path包含了文件夹、文件名、文明类型)、文件内容
/// </summary>
/// <param name="fs"></param>
/// <param name="path"></param>
/// <param name="fileContext"></param>
private void GetSavePathAndFileContextByte(Byte[] fs, out string savePath, out byte[] fileContext)
{
string folderStr = "C:\\Users\\lanmage2\\Desktop\\Server收\\";//文件夹的位置
string fileNameStr;//从客户端传输过来的文件名
int fileNameLong = 0;
byte[] fileNameLongByte = new byte[4];//固定四个字节,用来保存名字的长度。
byte[] fileNameByte = new byte[0];//初始化为0
byte[] fileContextByte = new byte[0];//初始化为0
int count = 0;
while (count < fs.Length)
{
if (count == 0)
{
//不做任何处理,方便逻辑的理解
}
else if ( (count > 0) && (count < 4 + 1 ) )
{
fileNameLongByte[count - 1] = fs[count];
fileNameLong = BitConverter.ToInt32(fileNameLongByte, 0);//将字节转化为整数,该整数位文件名的长度。
fileNameByte = new byte[fileNameLong];
fileContextByte = new byte[fs.Length - 1 - 4 - fileNameByte.Length];
}
else if ((count >= (4 + 1)) && (count < (fileNameByte.Length + 4 + 1)))
{
fileNameByte[count - 4 - 1] = fs[count];
}
else
{
fileContextByte[count - (fileNameByte.Length + 4 + 1)] = fs[count];
}
count++;
}
fileNameStr = Encoding.UTF8.GetString(fileNameByte);//将字节数组转为字符串
savePath = folderStr + fileNameStr;
fileContext = fileContextByte;
}
private void BtnSysShutDown_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
}
}
2.2、Client
MainWindow.xaml
<Window x:Class="Client.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Client"
mc:Ignorable="d"
Title="Client" Height="450" Width="850" HorizontalAlignment="Center" VerticalAlignment="Center" >
<Grid Height="400" Width="800">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="6*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Canvas Grid.Row="0" Background="#FF8080C6" >
<!--<Border Height="50" Background="#FF307ECA" Margin="23,11,16,358"/>-->
<Label Content="Server IP" Canvas.Left="49" Canvas.Top="13"/>
<Label Content="Server Port" Canvas.Left="332" Canvas.Top="13"/>
<Label Content="连接状态" Canvas.Left="555" Canvas.Top="13"/>
<TextBox x:Name="txtServer" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="127.0.0.1" VerticalAlignment="Top" Width="120" Canvas.Left="117" Canvas.Top="15"/>
<TextBox x:Name="txtPort" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="50000" VerticalAlignment="Top" Width="50" Canvas.Left="416" Canvas.Top="15"/>
<TextBox x:Name="txtBox_Connect" Text="未连接" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76" Margin="630,15,0,0" />
</Canvas>
<Canvas Grid.Row="1" Background="#FFCFCFDB" >
<TextBox x:Name="txtLog" HorizontalAlignment="Left" Height="185" TextWrapping="Wrap" VerticalAlignment="Top" Width="364" BorderBrush="#FF5700FF" Canvas.Top="9" Canvas.Left="26"/>
<Label Content="消息记录" Canvas.Left="328" Canvas.Top="13" Background="#FFDFC5C5"/>
<TextBox x:Name="txtSendMsg" HorizontalAlignment="Left" Height="83" TextWrapping="Wrap" VerticalAlignment="Top" Width="366" BorderBrush="#FF5700FF" Canvas.Top="205" Canvas.Left="24"/>
<Label Content="编辑消息" Canvas.Left="327" Canvas.Top="209" Background="#FFDFC5C5" RenderTransformOrigin="0.741,7.92"/>
<Border BorderBrush="#FF39222B" BorderThickness="2" Height="299" Width="342" Canvas.Left="448" Canvas.Top="-2"/>
<Border BorderBrush="#FF39222B" BorderThickness="2" Height="43" Width="342" Canvas.Left="448" Canvas.Bottom="0" Canvas.Top="254" Background="#FF0086FF"/>
<Image x:Name="Image_PlayImage" Height="243" Width="330" Canvas.Left="454" Canvas.Top="6"/>
</Canvas>
<Canvas Grid.Row="2" Background="#FF8080C6" >
<Button x:Name="btnSendMsg" Content="发送消息" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76" Click="btnSendMsg_Click" Canvas.Left="128" Canvas.Top="15"/>
<Button x:Name="btnOpenImage" Content="打开图片" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76" Click="btnOpenImage_Click" Canvas.Left="499" Canvas.Top="15"/>
<Button x:Name="btnSendImage" Content="发送图片" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76" Click="btnSendImage_Click" Canvas.Left="652" Canvas.Top="15"/>
<TextBox x:Name="txtFilePath" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="334" Canvas.Left="452" Canvas.Top="-35"/>
<Button x:Name="BtnSysShutDown" Content="退出" BorderThickness="2" Click="BtnSysShutDown_Click" Height="41" Width="71" Background="#FFA31D77" Canvas.Left="2" Canvas.Top="4" ></Button>
</Canvas>
</Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.Win32;
using System;
using System.Collections.Generic;
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;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace Server
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
string Receive_IPandPort = "";
public MainWindow()
{
InitializeComponent();
//当点击开始监听的时候,在服务器端创建一个负责监听IP地址跟端口号的Socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse("127.0.0.1");//IPAddress.Any;
//创建端口号对象
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
//监听
socketWatch.Bind(point);
ShowMsg("监听成功");
socketWatch.Listen(10);
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
}
public delegate void delegate1(string str);//定义委托
public delegate int delegate2(string endPoint);
Socket Server;
//将远程连接的客户端的IP地址和Socket存入集合中
Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
/// <summary>
/// 等待客户端的连接,并且创建与之通信的Socket
/// </summary>
/// <param name="o"></param>
void Listen(object o)
{
Socket socketWatch = o as Socket;
//等待客户端的连接,并且创建一个负责通信的Socket
while (true)
{
try
{
//负责跟客户端通信的Socket
Server = socketWatch.Accept();
//将远程连接的客户端的IP地址和Socket存入集合中
dicSocket.Add(Server.RemoteEndPoint.ToString(), Server);
//将远程连接的客户端的IP地址和端口号存储下拉框中
//cboUsers.Items.Add(Server.RemoteEndPoint.ToString());
//Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate2(cboUsers.Items.Add), Server.RemoteEndPoint.ToString());
Receive_IPandPort = Server.RemoteEndPoint.ToString();
//192.168.0.100:连接成功
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), Server.RemoteEndPoint.ToString() + ":" + "连接成功");
//开启一个新的线程,不停地接收客户端发送过来的消息
Thread th = new Thread(Receive);
th.IsBackground = true;
th.Start(Server);
}
catch { }
}
}
/// <summary>
/// 服务端不停地接收客户端发送过来的消息
/// </summary>
/// <param name="o"></param>
void Receive(object o)
{
Socket Server = o as Socket;
while (true)
{
try
{
//客户端连接成功后,服务器应该接收服务器应该接收客户端发来的消息
byte[] buffer = new byte[1024 * 1024 * 2];
//实际接收到的有效字节数
int r = Server.Receive(buffer);
if (r == 0)
{
break;
}
else if (buffer[0] == 0)
{
string str = Encoding.UTF8.GetString(buffer, 1, r-1);
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), "[接收]" + Server.RemoteEndPoint.ToString() + ":" + str);
}
else if (buffer[0] == 1)
{
string savePath;
byte[] fileContext = new byte[0];
GetSavePathAndFileContextByte(buffer, out savePath, out fileContext); //读取从客户端传输过来的文件名、文件内容
System.IO.File.WriteAllBytes(savePath, fileContext);//将内容写入到制定的路径。
//MessageBox.Show("保存图片成功");
ShowImage(savePath);
string fileName = System.IO.Path.GetFileName(savePath);
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), "[接收]" + Server.RemoteEndPoint.ToString() + ":" + "接收的图片或文件:" + fileName);
}
else if (buffer[0] == 2)
{
//Shock();
}
}
catch
{
//MessageBox.Show("你接收的是非法文件或非法消息");
}
}
}
private void ShowMsg(string str)
{
txtContent.AppendText(str + "\r\n");
}
private void ShowImage(string path)
{
this.Dispatcher.BeginInvoke((Action)delegate ()//异步委托,直接更新UI线程
{
//string fileName = System.IO.Path.GetFileName(path);
//Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), "[接收]" + Client.RemoteEndPoint.ToString() + ":" + "接收的图片或文件:" + fileName);
string ReceiveFileNameProperty_str = System.IO.Path.GetExtension(path); //获取后缀。
//必须判断,是图片执行,并显示。
if ((ReceiveFileNameProperty_str == ".jpg")
|| (ReceiveFileNameProperty_str == ".png")
|| (ReceiveFileNameProperty_str == ".bmp")
|| (ReceiveFileNameProperty_str == ".jpeg")
|| (ReceiveFileNameProperty_str == ".JPG")
|| (ReceiveFileNameProperty_str == ".PNG")
|| (ReceiveFileNameProperty_str == ".BMP")
|| (ReceiveFileNameProperty_str == ".JPEG"))
{
Image_PlayImage.Source = new BitmapImage(new Uri(path, UriKind.Absolute));//绝对路径
}
//btn_StartServer.Content = "接收完成";
}
);
}
/// <summary>
/// 服务器给客户端发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSendMsg_Click(object sender, RoutedEventArgs e)
{
string str = txtSendMsg.Text.Trim();
byte[] buffer = Encoding.UTF8.GetBytes(str);
List<byte> list = new List<byte>();
list.Add(0);
list.AddRange(buffer);
//将泛型集合转换为数组
byte[] newBuffer = list.ToArray();
//获得用户在下拉框中选中的IP地址
//string ip = cboUsers.SelectedItem.ToString();
//dicSocket[ip].Send(newBuffer);
dicSocket[Receive_IPandPort].Send(newBuffer);
txtSendMsg.Text = "";
//发送时,也要在消息显示发送的消息。
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), "[发送]" + Server.RemoteEndPoint.ToString() + ":" + str);
}
/// <summary>
/// 选择要发送的文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnChooseFile_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.InitialDirectory = "C:\\Users\\Administrator\\Desktop\\Server发";
//ofd.Title = "请选择要发送的文件";
//ofd.Filter = "所有文件|*.*";
ofd.ShowDialog();
txtFilePath.Text = ofd.FileName;
ShowImage(txtFilePath.Text);
}
private void btnSendFile_Click(object sender, RoutedEventArgs e)
{
string path = txtFilePath.Text;//文件的路径
string fileName = System.IO.Path.GetFileName(path);
Byte[] fileNameByte = GetFileNameByte(fileName);//文件名的字节数。
Byte[] fileContentByte = GetfileContentByte(path);//文件内容。
Byte[] combomArray = GetCombomFileByte(fileNameByte, fileContentByte);//总发送的内容。
//dicSocket[cboUsers.SelectedItem.ToString()].Send(combomArray, 0, combomArray.Length, SocketFlags.None);
dicSocket[Receive_IPandPort].Send(combomArray, 0, combomArray.Length, SocketFlags.None);
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new delegate1(ShowMsg), "[发送]" + Server.RemoteEndPoint.ToString() + ":" + "已经发送图片或文件:" + fileName);
}
private Byte[] GetFileNameByte(string SendFileName_str)
{
byte[] fileNameByteVar = System.Text.Encoding.UTF8.GetBytes(SendFileName_str);
return fileNameByteVar;
}
private Byte[] GetfileContentByte(string path)
{
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);//读取文件
Byte[] fileContentByteVar = new Byte[fs.Length];
try
{
fs.Read(fileContentByteVar, 0, fileContentByteVar.Length);
fs.Close();
//return fileContentByteVar;
}
catch
{
MessageBox.Show("获取文件内容字节失败");
//return fileContentByteVar;
}
return fileContentByteVar;
}
/// <summary>
/// 四部分,第一部分为1B,区分发送类型,即指令或文件。二部分为4B,保存文件名所占的字符串长度。三部分,保存文件名的内容。四部分,文件的正式内容。
/// </summary>
/// <param name="fileNameByte"></param>
/// <param name="fileContentByte"></param>
/// <returns></returns>
private Byte[] GetCombomFileByte(Byte[] fileNameByte, Byte[] fileContentByte)
{
int fileNameLong = fileNameByte.Length;//将文件的长度保存为一个整数。
byte[] fileNameLongByte = new byte[4];//将整数放在4个字节中传输。
fileNameLongByte = BitConverter.GetBytes(fileNameLong);//一个int等于四个字节。
int combomFileLong = 1 + fileNameByte.Length + fileNameLongByte.Length + fileContentByte.Length;//总字节长度
Byte[] combomFileByteTemple = new byte[combomFileLong];
for (int i = 0; i < combomFileLong; i++)
{
if (i == 0)//区分发送类型,即指令或文件
{
combomFileByteTemple[0] = 1;// 1表示发送文件
}
else if ((i > 0) && (i < (fileNameLongByte.Length + 1)))//确认文件名的长度,四个字节保存。
{
combomFileByteTemple[i] = fileNameLongByte[i-1];
}
else if ( (i >= (fileNameLongByte.Length + 1)) && (i < (fileNameByte.Length + fileNameLongByte.Length + 1)) )//文件名的内容
{
combomFileByteTemple[i] = fileNameByte[i - fileNameLongByte.Length - 1];//从第0号位置读取fileNameByte
}
else
{
combomFileByteTemple[i] = fileContentByte[i - fileNameByte.Length - fileNameLongByte.Length - 1];//从第0号位置读取fileContentByte
}
}
return combomFileByteTemple;
}
/// <summary>
/// 获取文件路径path(path包含了文件夹、文件名、文明类型)、文件内容
/// </summary>
/// <param name="fs"></param>
/// <param name="path"></param>
/// <param name="fileContext"></param>
private void GetSavePathAndFileContextByte(Byte[] fs, out string savePath, out byte[] fileContext)
{
string folderStr = "C:\\Users\\lanmage2\\Desktop\\Server收\\";//文件夹的位置
string fileNameStr;//从客户端传输过来的文件名
int fileNameLong = 0;
byte[] fileNameLongByte = new byte[4];//固定四个字节,用来保存名字的长度。
byte[] fileNameByte = new byte[0];//初始化为0
byte[] fileContextByte = new byte[0];//初始化为0
int count = 0;
while (count < fs.Length)
{
if (count == 0)
{
//不做任何处理,方便逻辑的理解
}
else if ( (count > 0) && (count < 4 + 1 ) )
{
fileNameLongByte[count - 1] = fs[count];
fileNameLong = BitConverter.ToInt32(fileNameLongByte, 0);//将字节转化为整数,该整数位文件名的长度。
fileNameByte = new byte[fileNameLong];
fileContextByte = new byte[fs.Length - 1 - 4 - fileNameByte.Length];
}
else if ((count >= (4 + 1)) && (count < (fileNameByte.Length + 4 + 1)))
{
fileNameByte[count - 4 - 1] = fs[count];
}
else
{
fileContextByte[count - (fileNameByte.Length + 4 + 1)] = fs[count];
}
count++;
}
fileNameStr = Encoding.UTF8.GetString(fileNameByte);//将字节数组转为字符串
savePath = folderStr + fileNameStr;
fileContext = fileContextByte;
}
private void BtnSysShutDown_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
}
}
三、Socket异步通信实现
请参考 https://www.cnblogs.com/liuyong/archive/2011/09/08/1892217.html