У меня есть проблема безопасности потоков.
У меня есть два принтера, один загружен с маленькой этикеткой, а другой большой. Я хочу отправить 1 задание на печать через сокет на каждый принтер.
Я попытался обработать / обработать фон первого запроса (большая метка), так как это может занять много времени.
99% времени скрипт работает как положено. Маленькие и большие этикетки выходят из соответствующих принтеров.
Однако время от времени как большие, так и маленькие этикетки отправляются на один и тот же принтер! Либо как маленький, так и большой.
Я думаю, что это связано с безопасностью потоков, но мне очень трудно отследить и понять, что происходит. Я пытался добавить блокировку и закрыть сокеты после использования, но что бы я ни пытался, проблема остается.
Я пытался сократить мой код до минимума, но знаю, что этот пост все еще очень тяжелый. Любой совет будет принята с благодарностью.
// stores the printer info
class PrinterBench
{
public PrinterBench(string sArg_PostageLabelIP, string sArg_SmallLabelIP)
{
PostageLabelIP = sArg_PostageLabelIP;
SmallLabelIP = sArg_SmallLabelIP;
}
public string PostageLabelIP;
public string SmallLabelIP;
}
// main entry point
class HomeController{
PrintController oPrintController;
List<string> lsLabelResults = new List<string>("label result");
PrinterBench pbBench = new PrinterBench("192.168.2.20","192.168.2.21");
void Process(){
oPrintController = new PrintController(this);
if(GetLabel()){
// should always come out of the big printer (runs in background)
oPrintController.PrintBySocketThreaded(lsLabelResults, pbBench.PostageLabelIP);
// should always come out of the small printer
oPrintController.PrintWarningLabel();
}
}
}
class PrintController{
HomeController oHC;
public EndPoint ep { get; set; }
public Socket sock { get; set; }
public NetworkStream ns { get; set; }
private static Dictionary<string, Socket> lSocks = new Dictionary<string, Socket>();
private BackgroundWorker _backgroundWorker;
static readonly object locker = new object();
double dProgress;
bool bPrintSuccess = true;
public PrintController(HomeController oArg_HC)
{
oHC = oArg_HC;
}
public bool InitSocks()
{
// Ensure the IP's / endpoints of users printers are assigned
if (!lSocks.ContainsKey(oHC.pbBench.PostageLabelIP))
{
lSocks.Add(oHC.pbBench.PostageLabelIP, null);
}
if (!lSocks.ContainsKey(oHC.pbBench.SmallLabelIP))
{
lSocks.Add(oHC.pbBench.SmallLabelIP, null);
}
// attempt to create a connection to each socket
foreach (string sKey in lSocks.Keys.ToList())
{
if (lSocks[sKey] == null || !lSocks[sKey].Connected )
{
ep = new IPEndPoint(IPAddress.Parse(sKey), 9100);
lSocks[sKey] = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
lSocks[sKey].Connect(ep);
}
}
return true;
}
public bool PrintBySocketThreaded(List<string> lsToPrint, string sIP)
{
// open both the sockets
InitSocks();
bBatchPrintSuccess = false;
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
_backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.WorkerSupportsCancellation = true;
object[] parameters = new object[] { lsToPrint, sIP, lSocks };
_backgroundWorker.RunWorkerAsync(parameters);
return true;
}
// On worker thread, send to print!
public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
object[] parameters = e.Argument as object[];
double dProgressChunks = (100 / ((List<string>)parameters[0]).Count);
int iPos = 1;
Dictionary<string, Socket> dctSocks = (Dictionary<string, Socket>)parameters[2];
foreach (string sLabel in (List<string>)parameters[0] )
{
bool bPrinted = false;
// thread lock print by socket to ensure its not accessed twice
lock (locker)
{
// get relevant socket from main thread
bPrinted = PrintBySocket(sLabel, (string)parameters[1], dctSocks[(string)parameters[1]]);
}
iPos++;
}
while (!((BackgroundWorker)sender).CancellationPending)
{
((BackgroundWorker)sender).CancelAsync();
((BackgroundWorker)sender).Dispose();
//Thread.Sleep(500);
}
return;
}
// Back on the 'UI' thread so we can update the progress bar (have access to main thread data)!
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null) MessageBox.Show(e.Error.Message);
if (bPrintSuccess) oHC.WriteLog("Printing Complete");
bBatchPrintSuccess = true;
((BackgroundWorker)sender).CancelAsync();
((BackgroundWorker)sender).Dispose();
}
/// sends to printer via socket
public bool PrintBySocket(string sArg_ToPrint, string sIP, Socket sock = null)
{
Socket sTmpSock = sock;
if (sTmpSock == null)
{
InitSocks();
if (!lSocks.ContainsKey(sIP)){
throw new Exception("Sock not init");
}else{
sTmpSock = lSocks[sIP];
}
}
using (ns = new NetworkStream(sTmpSock))
{
byte[] toSend = Encoding.ASCII.GetBytes(sEOL + sArg_ToPrint);
ns.BeginWrite(toSend, 0, toSend.Length, OnWriteComplete, null);
ns.Flush();
}
return true;
}
public bool PrintWarningLabel()
{
string sOut = sEOL + "N" + sEOL;
sOut += "LL411" + sEOL;
sOut += "R40,0" + sEOL;
sOut += "S5" + sEOL;
sOut += "D15" + sEOL;
sOut += "A0,0,0,4,4,3,N,\"!!!!!!!!!!!!!!!!!!!!!!!\"" + sEOL;
sOut += "A0,150,0,4,3,3,N,\"WARNING MESSAGE TO PRINT\"" + sEOL;
sOut += "A0,280,0,4,4,3,N,\"!!!!!!!!!!!!!!!!!!!!!!!\"" + sEOL;
sOut += "P1";
sOut += sEOL;
if (PrintBySocket(sOut, oHC.pbBench.SmallLabelIP))
{
oHC.WriteLog("WARNING LABEL PRINTED");
return true;
}
return false;
}
}