2020년 9월 1일 화요일

QTcpSocket 외부 쓰레드에서 write 하는 방법

 QTcpSocket 은 생성된 쓰레드 외에 다른 쓰레드에서 write 를 시도할 경우 에러를 리턴하며 전송이 되지않는다. 이럴 경우 아래와 같이 이벤트를 발생시켜 생성 쓰레드에서 write 처리를 하도록해서 문제를 해결할 수 있다.


 #ifndef TCPAUDIOSENDER_H  
 #define TCPAUDIOSENDER_H  
 #include <QThread>  
 #include <QTcpServer>  
 #include <QTcpSocket>  
 #include <QMutex>  
 #include "logwriter.h"  
 #include "bufferqueue.h"  
 class TcpAudioSender : public QThread  
 {  
   Q_OBJECT  
 public:  
   explicit TcpAudioSender(BufferQueue<AudioBuffer> *pSendQue, QThread *parent = 0);  
   virtual ~TcpAudioSender();  
 signals:  
   void socketWriteEvent(QTcpSocket *sock, AudioBuffer *buffer);  
 public slots:  
   void onNewConnection();  
   void onSocketStateChanged(QAbstractSocket::SocketState socketState);  
   void onReadyRead();  
   void onSocketWrite(QTcpSocket *sock, AudioBuffer *buffer);  
 public:  
   bool startServer(int port);  
   void stopServer();  
 protected:  
   virtual void run() override;  
 protected:  
   bool      m_bRun;  
   QTcpServer*     m_pServer;  
   int         m_nPort;  
   QList<QTcpSocket*> m_clientList;  
   QMutex       m_clientListMutex;  
   BufferQueue<AudioBuffer>*  m_pSendQue;  
   LogWriter*   m_pLogWriter;  
 };  
 #endif // TCPAUDIOSENDER_H  



 #include "tcpaudiosender.h"  
 TcpAudioSender::TcpAudioSender(BufferQueue<AudioBuffer> *pSendQue, QThread *parent) : QThread(parent)  
 {  
   m_bRun = false;  
   m_pServer = new QTcpServer(this);  
   m_pSendQue = pSendQue;  
   m_pLogWriter = LogWriter::getInstance();  
 }  
 TcpAudioSender::~TcpAudioSender()  
 {  
   delete m_pServer;  
 }  
 bool TcpAudioSender::startServer(int port)  
 {  
   if (!m_pServer->listen(QHostAddress::Any, port)) {  
     m_pLogWriter->writeLog(QString("TcpAudioSender cannot open %1 port").arg(port));  
     return false;  
   }  
   m_nPort = port;  
   connect(m_pServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));  
   connect(this, SIGNAL(socketWriteEvent(QTcpSocket*, AudioBuffer*)), this, SLOT(onSocketWrite(QTcpSocket*, AudioBuffer*)));  
   m_bRun = true;  
   QThread::start();  
   return true;  
 }  
 void TcpAudioSender::stopServer()  
 {  
   m_pServer->close();  
   m_bRun = false;  
   QThread::wait();  
 }  
 void TcpAudioSender::onNewConnection()  
 {  
   QTcpSocket *clientSocket = m_pServer->nextPendingConnection();  
   connect(clientSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));  
   connect(clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));  
   m_clientListMutex.lock();  
   m_clientList.push_back(clientSocket);  
   m_clientListMutex.unlock();  
 }  
 void TcpAudioSender::onSocketStateChanged(QAbstractSocket::SocketState socketState)  
 {  
   if (socketState == QAbstractSocket::UnconnectedState)  
   {  
     QTcpSocket* sender = static_cast<QTcpSocket*>(QObject::sender());  
     m_clientListMutex.lock();  
     m_clientList.removeOne(sender);  
     m_clientListMutex.unlock();  
   }  
 }  
 void TcpAudioSender::onReadyRead()  
 {  
   /*  
   QTcpSocket* sender = static_cast<QTcpSocket*>(QObject::sender());  
   QByteArray datas = sender->readAll();  
   for (QTcpSocket* socket : m_clientList) {  
     if (socket != sender)  
       socket->write(QByteArray::fromStdString(sender->peerAddress().toString().toStdString() + ": " + datas.toStdString()));  
   }  
   */  
 }  
 void TcpAudioSender::onSocketWrite(QTcpSocket *sock, AudioBuffer *buffer)  
 {  
   int res = sock->write(buffer->data, buffer->size);  
   if (res != buffer->size) {  
     qDebug() << QString("TcpAudioSender(%1) cannot send client : %2, %3").arg(m_nPort).arg(res).arg(buffer->size);  
   }  
   delete buffer;  
   //qDebug() << "TcpAudioSender send :" << size << "bytes";  
 }  
 void TcpAudioSender::run()  
 {  
   while (m_bRun)  
   {  
     AudioBuffer *buffer = m_pSendQue->pop();  
     if (!buffer) {  
       usleep(10);  
       continue;  
     }  
     m_clientListMutex.lock();  
     for (QTcpSocket* socket : m_clientList) {  
       AudioBuffer *sendBuffer = new AudioBuffer(buffer->data, buffer->size);  
       emit socketWriteEvent(socket, sendBuffer);  
     }  
     m_clientListMutex.unlock();  
     delete buffer;  
   }  
 }  


2020년 7월 22일 수요일

간단한 Qt Thread 사용법

< MyThread.h>

class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QThread *parent = 0);
virtual ~MyThread();

void startThread();
void stopThread();

protected:
virtual void run();

signals:
void started();
void finished();

protected:
bool m_bRun;
}



< MyThread.cpp>

MyThread::MyThread(QThread *parent) : QThread(parent);
{
m_bRun = false;
}

MyThread::~MyThread()
{
}

void MyThread::startThread()
{
m_bRun = true;
QThread::start();
}

void MyThread::stopThread()
{
m_bRun = false;
QThread::wait();
}

void MyThread::run()
{
emit started();

while (m_bRun)
{
...
}

emit finished();
}

2020년 6월 24일 수요일

윈도우10 부팅시 관리자 권한으로 자동실행하는 법

윈도우 부팅시 프로그램을 자동실행하는 가장 쉬운 방법은 실행창에서 shell:startup 을 쳐서 
시작 프로그램에 실행 프로그램이나 바로가기를 복사해서 등록하는 방법이 있다.
하지만 이 방법을 사용할 경우 바로가기가 "관리자 권한으로 실행" 속성이 있는 경우 부팅을
해도 실행이 되지않는다. 
윈도우 부팅시 일반 프로그램을 관리자 권한으로 자동 실행하려면 아래와 같이 하면된다.

1. 윈도우의 UAC(User Access Control) 끄기
2. 바탕화면에 프로그램의 바로가기 생성
3. 바로가기 -> 속성 -> 바로가기의 고급 선택 -> 관리자 권한으로 실행 체크
4. cmd.exe 창 실행하여 c:\Users\<유저이름>\Desktop 아래에서 dir 명령으로 바로가기 이름 체크 -> MyApp Shortcut.lnk 라고 가정
5. 레지스트리 에디터 실행
6. 64비트 윈도우 기준 =>
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run 
아래에 문자열 속성으로 키 생성해서 이름 적당히 입력하고 값 데이터에 4번에서 알아낸 전체 경로 입력 => c:\Users\<유저이름>\Desktop\MyApp Shortcut.lnk

이렇게 하면 부팅할때마다 관리자 권한이 없는 일반 프로그램을 UAC 체크없이 자동으로 관리자 권한으로 실행할 수 있다.


 

2019년 11월 14일 목요일

avformat_open_input rtsp connection timeout 주기

ffmpeg demuxer 를 사용해서 rtsp client 를 구현할때 접속이 되지않으면 avformat_open_input 에서 무한 블러킹이 걸린다. 이때 아래와 같이 타임아웃을 주면 avformat_open_input 을 빠져나올수 있다.


AVDictionary* dicts = NULL;

av_dict_set(&dicts, "stimeout", "2000000", 0);

int err = avformat_open_input(&m_pFormatCtx, filepath, NULL, &dicts);

2019년 7월 10일 수요일

c# 시스템 메모리 사용량 구하기

전체 메모리 사용량 구하는 법을 검색해봤는데 의외로 쓸만한 소스가 없었다.
겨우 찾아낸 이 방법이 제일 나은것 같다.

출처 - https://ash84.net/2012/03/03/c-wmi-eb-a5-bc--ec-9d-b4-ec-9a-a9-ed-95-9c--ed-98-84-ec-9e-ac--eb-a9-94-eb-aa-a8-eb-a6-ac--ec-82-ac-ec-9a-a9-eb-9f-89--ea-b5-ac-ed-95-98-ea-b8-b0/

프로세스 메모리 사용량이 아닌 작업관리자에 나오는 시스템 메모리 사용량 체크 소스이다.

     private uint GetTotalUsedMemory()  
     {  
       ManagementClass cls = new ManagementClass("Win32_OperatingSystem");  
       ManagementObjectCollection instances = cls.GetInstances();  
   
       foreach (ManagementObject info in instances)  
       {  
         int total_physical_memeory = int.Parse(info["TotalVisibleMemorySize"].ToString());  
         int free_physical_memeory = int.Parse(info["FreePhysicalMemory"].ToString());  
         int remain_physical_memory = total_physical_memeory - free_physical_memeory;  
   
         Console.WriteLine("Memory Information ================================");  
         Console.WriteLine("Total Physical Memory :{0:#,###} KB", info["TotalVisibleMemorySize"]);  
         Console.WriteLine("Free Physical Memory :{0:#,###} MB", info["FreePhysicalMemory"]);  
   
         Console.WriteLine("Memory Usage Percent = {0} %", 100 * remain_physical_memory / total_physical_memeory);  
         Console.WriteLine("Remain Physical Memory : {0:#,###}", remain_physical_memory);  
   
         return (uint)(remain_physical_memory / 1000);  
       }  
       return 0;  
   


2019년 7월 4일 목요일

c# unix timestamp local DateTime 으로 변환

int timestamp;    // unix timestamp
DateTime dateTimeTimestamp;
...
dateTimeTimestamp = new DateTime(1970, 1, 1).AddSeconds(timestamp);
dateTimeTimestamp += TimeZone.CurrentTimeZone.GetUtcOffset(dateTimeTimestamp);

2019년 7월 2일 화요일

c# simple thread-safe Log Writer

싱글턴 패턴으로된 로그파일을 생성해주는 클래스이다.
로그파일은 날짜별로 생성되고 각 로그 시간을 함께 찍어준다.
프로그램 시작시 StartDeleteLog / 종료시 StopDeleteLog 한다.
로그파일은 디폴트로 30일이 넘으면 삭제된다.


1:  using System;  
2:  using System.Collections.Generic;  
3:  using System.IO;  
4:  using System.Linq;  
5:  using System.Text;  
6:  using System.Threading;  
7:  using System.Threading.Tasks;  
8:    
9:  namespace MyLog  
10:  {  
11:    public enum LogType  
12:    {  
13:      Info,  
14:      Exception,  
15:      Error  
16:    }  
17:    
18:    public class LogWriter  
19:    {  
20:      public delegate void LogWriteHandlerFunc(LogType logType, DateTime logTime, string logMessage);  
21:      public LogWriteHandlerFunc LogWriteHandler;  
22:    
23:      private static LogWriter instance = new LogWriter();  
24:      public static LogWriter Instance { get { return instance; } }  
25:    
26:      private object objLogLock = new object();  
27:    
28:      private const string LOG_PATH = @"C:\Log\";  
29:      private const string LOG_FILENAME = @"log";  
30:    
31:      private Thread threadDeleteLog;  
32:      private bool bThreadDeleteLogRun = false;  
33:      private int logDeleteDays = 30;  
34:    
35:      public void StartDeleteLog(int days)  
36:      {  
37:        if (!bThreadDeleteLogRun)  
38:        {  
39:          logDeleteDays = days;  
40:          bThreadDeleteLogRun = true;  
41:          threadDeleteLog = new Thread(new ThreadStart(ThreadDeleteLog));  
42:          threadDeleteLog.IsBackground = true;  
43:          threadDeleteLog.Start();  
44:        }  
45:      }  
46:    
47:      public void StopDeleteLog()  
48:      {  
49:        if (threadDeleteLog != null)  
50:        {  
51:          bThreadDeleteLogRun = false;  
52:          threadDeleteLog.Join();  
53:        }  
54:      }  
55:    
56:      private void ThreadDeleteLog()  
57:      {  
58:        CheckLogPath(LOG_PATH);  
59:    
60:        DateTime lastTime = DateTime.MinValue;  
61:    
62:        while (bThreadDeleteLogRun)  
63:        {  
64:          DateTime now = DateTime.Now;  
65:          double diff = (now - lastTime).TotalHours;  
66:          if (diff < 0) diff = 0;  
67:    
68:          if (diff > 24)  
69:          {  
70:            try  
71:            {  
72:              string[] filepaths = Directory.GetFiles(LOG_PATH, "*.txt");  
73:              DeleteLogFiles(now, filepaths);  
74:            }  
75:            catch (Exception ex)  
76:            {  
77:              WriteLog(LogType.Exception, ex.ToString());  
78:            }  
79:    
80:            lastTime = now;  
81:          }  
82:    
83:          Thread.Sleep(100);  
84:        }  
85:      }  
86:    
87:      private void DeleteLogFiles(DateTime now, string[] filepaths)  
88:      {  
89:        foreach (string filepath in filepaths)  
90:        {  
91:          try  
92:          {  
93:            DateTime date = File.GetCreationTime(filepath);  
94:            if ((now - date).TotalDays > logDeleteDays)  
95:            {  
96:              File.Delete(filepath);  
97:            }  
98:          }  
99:          catch (Exception ex)  
100:          {  
101:            WriteLog(LogType.Exception, ex.ToString());  
102:          }  
103:        }  
104:      }  
105:    
106:      public void WriteLog(LogType logType, string log)  
107:      {  
108:        try  
109:        {  
110:          lock (objLogLock)  
111:          {  
112:            Console.WriteLine(log);  
113:    
114:            string filepath = LOG_PATH;  
115:    
116:            CheckLogPath(filepath);  
117:    
118:            DateTime dateTime = DateTime.Now;  
119:            string strDate = dateTime.ToString("yyyyMMdd");  
120:            string strDateTime = dateTime.ToString("yyyy-MM-dd HH:mm:ss.fff");  
121:    
122:            filepath = string.Format("{0}{1}_{2}.txt", filepath, LOG_FILENAME, strDate);  
123:            string logMessage = string.Format("{0} [{1}] {2}", strDateTime, logType, log);  
124:    
125:            using (StreamWriter sw = File.AppendText(filepath))  
126:            {  
127:              sw.WriteLine(logMessage);  
128:              sw.WriteLine("---------------------------------------------------------------------------------------\r");  
129:              sw.Flush();  
130:            }  
131:    
132:            if (LogWriteHandler != null) LogWriteHandler(logType, dateTime, log);  
133:          }  
134:        }  
135:        catch (Exception ex)  
136:        {  
137:          Console.WriteLine(ex.ToString());  
138:        }  
139:      }  
140:    
141:      private void CheckLogPath(string path)  
142:      {  
143:        try  
144:        {  
145:          if (!Directory.Exists(path))  
146:            Directory.CreateDirectory(path);  
147:        }  
148:        catch (Exception ex)  
149:        {  
150:          Console.WriteLine(ex.ToString());  
151:        }  
152:      }  
153:    }  
154:  }  
155:    


private LogWriter logWriter = LogWriter.Instance;
...
logWriter.StartDeleteLog(30);
...
logWriter.WriteLog(LogType.Info, "로그 시작...");
...
logWriter.StopDeleteLog();