鱼C论坛

 找回密码
 立即注册
查看: 2150|回复: 13

Socket接收的数据用WritePrinter写入打印机被分为若干个文件错误

[复制链接]
发表于 2024-7-20 11:53:39 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
我用Socket方式接收一个tcp数据包存为byte数据,每次接收1024个字节,然后将byte转为16进制进行内容替换后再转为byte数据,再将byte数据用OpenPrinter、StartDocPrinter、StartPagePrinter、WritePrinter、EndPagePrinter、EndDocPrinter、ClosePrinter等Api写入打印机,但现在遇到一个问题,它会把原本同一数据写入到打印机驱动里就变成了若干个1024字节的任务,我是想让它在打印队列里还是一个完整的任务应该怎么做?这个数据可以通过判断接收数据的头部特征十六进制代码52454D4F5445315449就打开打印机句柄并写入打印机队列任务,如果数据里包含结尾特征十六进制代码4A450100001B000000就结束打印并关闭打印机句柄,而没有发现这两个代码的数据就一直让它追加写入同一个打印任务





  1. using System.Net.Sockets;
  2. using System.Net;
  3. using System.Runtime.InteropServices;

  4. namespace fsd
  5. {
  6.     public partial class Form1 : Form
  7.     {
  8.         public Form1()
  9.         {
  10.             InitializeComponent();
  11.         }

  12.         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  13.         public class DOCINFOA
  14.         {
  15.             [MarshalAs(UnmanagedType.LPStr)]
  16.             public string pDocName;
  17.             [MarshalAs(UnmanagedType.LPStr)]
  18.             public string pOutputFile;
  19.             [MarshalAs(UnmanagedType.LPStr)]
  20.             public string pDataType;
  21.         }
  22.         [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  23.         public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

  24.         [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  25.         public static extern bool ClosePrinter(IntPtr hPrinter);

  26.         [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  27.         public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

  28.         [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  29.         public static extern bool EndDocPrinter(IntPtr hPrinter);

  30.         [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  31.         public static extern bool StartPagePrinter(IntPtr hPrinter);

  32.         [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  33.         public static extern bool EndPagePrinter(IntPtr hPrinter);

  34.         [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  35.         public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);




  36.         private static bool SendBytesToPrinter(string printerName, IntPtr intptrBytes, Int32 count)
  37.         {
  38.             Int32 error = 0, written = 0;
  39.             IntPtr intptrPrinter = new IntPtr(0);
  40.             DOCINFOA di = new DOCINFOA();
  41.             bool bSuccess = false;

  42.             di.pDocName = "Test Document";
  43.             di.pDataType = "RAW";

  44.             if (OpenPrinter(printerName.Normalize(), out intptrPrinter, IntPtr.Zero))
  45.             {
  46.                 if (StartDocPrinter(intptrPrinter, 1, di))
  47.                 {
  48.                     if (StartPagePrinter(intptrPrinter))
  49.                     {
  50.                         bSuccess = WritePrinter(intptrPrinter, intptrBytes, count, out written);
  51.                         EndPagePrinter(intptrPrinter);
  52.                     }
  53.                     EndDocPrinter(intptrPrinter);
  54.                 }
  55.                 ClosePrinter(intptrPrinter);
  56.             }
  57.             if (bSuccess == false)
  58.             {
  59.                 error = Marshal.GetLastWin32Error();
  60.             }
  61.             return bSuccess;
  62.         }
  63.         Socket _socket;
  64.         Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();

  65.         private void checkBox1_CheckedChanged(object sender, EventArgs e)
  66.         {
  67.             if (checkBox1.Checked)
  68.             {
  69.                 _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  70.                 IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.58"), 9178);
  71.                 try
  72.                 {
  73.                     _socket.Bind(endpoint);

  74.                 }
  75.                 catch (Exception ee)
  76.                 {
  77.                     MessageBox.Show("连接失败");
  78.                 }
  79.                 _socket.Listen(10);


  80.                 while (true)
  81.                 {
  82.                     Socket sockClient = _socket.Accept();
  83.                     while (true)
  84.                     {
  85.                         byte[] Receivedata = new byte[1024];
  86.                         int length = -1;
  87.                         try
  88.                         {
  89.                             length = sockClient.Receive(Receivedata);
  90.                         }
  91.                         catch
  92.                         {
  93.                             break;
  94.                         }

  95.                         if (length == 0)
  96.                         {
  97.                             sockClient.Close();
  98.                             break;
  99.                         }
  100.                         else
  101.                         {
  102.                             string data = BitConverter.ToString(Receivedata);
  103.                             data = data.Replace("-", "");                                                         
  104.                             int Data_head = data.IndexOf("52454D4F5445315449");
  105.                             int End_data = data.IndexOf("4A450100001B000000");
  106.                             if (data.Contains("804420FB00144008020820820040411101"))
  107.                             {
  108.                                 data = data.Replace("804420FB00144008020820820040411101", "5A4420FB001440080345A33C0040411108");
  109.                             }




  110.                             string printer_name = "Printer Name";
  111.                             byte[] outdata = Enumerable.Range(0, data.Length)
  112.                                         .Where(x => x % 2 == 0)
  113.                                         .Select(x => Convert.ToByte(data.Substring(x, 2), 16))
  114.                                         .ToArray();
  115.                             IntPtr pUnmanagedBytes = Marshal.AllocCoTaskMem(outdata.Length);
  116.                             Marshal.Copy(outdata, 0, pUnmanagedBytes, outdata.Length);

  117.                             if (pUnmanagedBytes != 0)
  118.                             {
  119.                                 SendBytesToPrinter(printer_name, pUnmanagedBytes, outdata.Length);
  120.                             }
  121.                         }
  122.                     }
  123.                 }
  124.             }
  125.             else
  126.             {
  127.                 _socket.Close();
  128.             }
  129.         }
  130.     }

  131. }
复制代码



小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2024-7-20 12:03:36 | 显示全部楼层
FishC 发表于 2024-7-20 11:55
哇,这个问题绝对是打破了我的鱼缸。看来您需要解决的是数据接收和处理的问题,以确保它们能够作为一个完整 ...

不能拼接完成再打印,因为拼接完成数据会很大,有些文件大小在1G以上,有的5G大小,这样需要很长的拼接时间,而且会出现内存错误,所以需要边接收边替换边打印
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-7-23 08:15:41 | 显示全部楼层
FishC 发表于 2024-7-20 12:04
明白了,既然拼接整合成完整数据会引发内存错误,我们需要在接收数据的过程中,以流式处理的方式尽量保 ...

经过你的方法已经成功,如果我想把接收的同一个数据分块分别写入2个或者多个打印机怎么写代码呢?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-7-23 09:00:22 | 显示全部楼层
FishC 发表于 2024-7-23 08:16
太好了,很高兴知道之前的方法能够成功!现在,让我们来实现将接收到的同一份数据分块分别写入多个打印 ...

private Dictionary dicSocket = new Dictionary();这一句有问题,需要两个参数
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-7-23 09:17:42 | 显示全部楼层
FishC 发表于 2024-7-23 08:16
太好了,很高兴知道之前的方法能够成功!现在,让我们来实现将接收到的同一份数据分块分别写入多个打印 ...

当同一数据分块分别写入多个打印机时你这一句代码有问题,缺少2个参数private Dictionary dicSocket = new Dictionary();
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-7-23 10:10:51 | 显示全部楼层
FishC 发表于 2024-7-23 09:18
抱歉给您带来了困扰!确实,声明一个 `Dictionary` 时需要指定键和值的数据类型。让我们正确地定义这个 ...

这段代码有2个问题

第1个问题是Checkbox取消选择后会在Socket sockClient = _socket.Accept();此出出现错误System.Net.Sockets.SocketException:“一个封锁操作被对 WSACancelBlockingCall 的调用中断。”

第2个问题是,分块打印到多个打印机时,只有打印机名称数组中最后一个打印机是写入完整的数据,其它的打印机只接收到空数据
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-7-23 13:06:32 | 显示全部楼层
FishC 发表于 2024-7-23 10:11
感谢您的反馈!我们来逐个解决这两个问题。

### 问题 1:Checkbox取消选择后Socket.Accept抛出异常
...

这段代码只是解决了异常问题,但还是和之前一样,只有打印机名称数组里最后一个打印机可以接收到完整的数据,而数组前面所有的打印机只能接收到空数据,我昨天试了很多次和现在一样的效果,始终不知道问题出在哪里
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-9-26 05:53

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表