CAsyncSocket网络编程问题

Pingo520 2017-02-21 10:19:47
先上代码

BOOL COnlineMonitorDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
hObject = ::CreateMutex(NULL, FALSE, _T("Mutex20170217"));
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(hObject);

MessageBox(_T("应用程序已经在运行"), _T("提示"), MB_ICONERROR | MB_OK);
DestroyWindow();
return FALSE;
}
// 将“关于...”菜单项添加到系统菜单中。

// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}

// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标

// TODO: 在此添加额外的初始化代码
server = new CMySocket(this);
char szName[256] = { 0 };
hostent *pHostent = gethostbyname(szName);
char* pszIP = inet_ntoa(*(in_addr*)pHostent->h_addr_list[0]);

if (!AfxSocketInit())
{
delete server;
server = NULL;
return FALSE;
}

if (!server->Socket())
{
delete server;
server = NULL;
return FALSE;
}

BOOL boptValue = FALSE;
int optValueLen = sizeof(boptValue);
server->SetSockOpt(SO_REUSEADDR, (void*)&boptValue, optValueLen, SOL_SOCKET);

if (!server->Bind(1024))
{
server->Close();
delete server;
server = NULL;
return FALSE;
}

if (!server->Listen())
{
server->Close();
delete server;
server = NULL;
return FALSE;
}
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void NTAPI ThreadFunc(PTP_CALLBACK_INSTANCE instance, PVOID context, PTP_WORK word)
{
/*CString s;
s.Format(_T("%d线程开始运行!"), GetCurrentThreadId());
AfxMessageBox(s);*/
BYTE* pData = (BYTE*)context;
delete[] pData;

}
void COnlineMonitorDlg::OnAccept()
{
CMySocket* m_recvSocket = new CMySocket(this);

if (!server->Accept(*m_recvSocket))
{
delete m_recvSocket;
m_recvSocket = NULL;
return;
}
socketList.AddTail(m_recvSocket);
}
void COnlineMonitorDlg::OnClose(CMySocket * msocket)
{
for (int i = 0; i < socketList.GetCount(); i++)
{
POSITION pos = socketList.FindIndex(i);
CMySocket* temp = socketList.GetAt(pos);
if (temp == msocket)
{
temp->Close();
delete temp;
socketList.RemoveAt(pos);
}
}
}
void COnlineMonitorDlg::OnReceive(CMySocket * recvSocke)
{
BYTE data[5] = { 0 };
int start = 0;
int n = 0;
if (n = recvSocke->Receive(data, 5))
{
CString header;
header.Format(_T("%02X%02X%02X"), data[0], data[1], data[2]);

UINT data_len = 0;
CString hex;
hex.Format(_T("%02X%02X"), data[3], data[4]);

data_len = Hex2Ten(hex);

BYTE *allData = new BYTE[data_len+7];
int sum = n;
while (sum < data_len + 7)
{
memcpy(allData + start, data, n);
start += n;

n = recvSocke->Receive(data, 5);
sum += n;
}
memcpy(allData + start, data, n);

PTP_WORK item = CreateThreadpoolWork(ThreadFunc, (PVOID)allData, NULL);
SubmitThreadpoolWork(item);
}
}

上面就是主要代码。
然后按F5进行调试,在onAccept,OnReceive,OnClose,ThreadFunc四处设置断点,用网络调试助手连接,发送一段数据,发现前面几次发送的数据server能够接收到,但是后面不管怎么发都接不到。也就是OnReceive在后面几次的发送中都不触发断点。断开调试助手的连接,发现会触发OnClose断点,说明TCP连接是没有断开的。然后用调试助手重新连接server,都正常,再发送数据,又是前面几次发送正常,后面就再也接收不到数据。
求问可能是什么原因造成的。调试i的时候还只开了一个连接进行测试。
...全文
198 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
Pingo520 2017-02-22
  • 打赏
  • 举报
回复
我这里要做的是与施工现场的监测设备连接的接收端,需要使用长连接,有心跳机制,而对于心跳数据只需要简单的回复处理。所以担心连接不释放,开的缓冲区和线程就一直占用着。 所以我开始的设计是用异步CAsyncSocket,有数据来的时候就读,直到接收到完整的数据包,然后new一个动态数组,传给线程池里的线程去处理。处理完了在线程里释放。 但是问题就是在CAsyncSocket,因为所有的socket都绑定到同一个窗口,造成所有的read消息都要通过同一个串口排序(不知道我理解 CAsyncSocket绑定窗口是否正确),如果因为一个连接的数据一次性没发完,就要等待接收,就会造成主线程卡的现象。 而且这边是小老板,服务器就是用的一台普通的PC,8G内存,如果连接少,每个连接单独开个工作线程和缓冲区没问题。怕就怕老板心大,要把别人所有的设备都连过来。 唉,先不管了,暂时这么做,一个连接单独开个工作线程和缓冲区,先完成再说。到时候连接太多出问题了,要老板自己换机子加内存去了。 如果大家有更好的设计,可以帮帮我啊
Pingo520 2017-02-22
  • 打赏
  • 举报
回复
引用 16 楼 zhao4zhong1 的回复:
深刻理解“‘池’化所有资源”这句话。
好的赵老师,我先一步一步的学,一个问题一个问题的解决先。
赵4老师 2017-02-22
  • 打赏
  • 举报
回复
深刻理解“‘池’化所有资源”这句话。
Pingo520 2017-02-22
  • 打赏
  • 举报
回复
引用 14 楼 zhujinqiang 的回复:
缓冲区 + 线程池
嗯,我现在在往这方面靠,原来没仔细想,把工作线程做成循环线程了,那样的话用线程池就没什么用。现在把工作线程设计成读取完一个完整的包就做处理,处理完就结束。就是别原来设计的要考虑的问题多些,更细致些,没其他问题了。自己慢慢学吧,唉
zhujinqiang 2017-02-22
  • 打赏
  • 举报
回复
缓冲区 + 线程池
赵4老师 2017-02-21
  • 打赏
  • 举报
回复
仅供参考:
//循环向a函数每次发送200个字节长度(这个是固定的)的buffer,
//a函数中需要将循环传进来的buffer,组成240字节(也是固定的)的新buffer进行处理,
//在处理的时候每次从新buffer中取两个字节打印
#ifdef _MSC_VER
    #pragma warning(disable:4996)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
    #include <windows.h>
    #include <process.h>
    #include <io.h>
    #define  MYVOID             void
    #define  vsnprintf          _vsnprintf
#else
    #include <unistd.h>
    #include <sys/time.h>
    #include <pthread.h>
    #define  CRITICAL_SECTION   pthread_mutex_t
    #define  MYVOID             void *
#endif
//Log{
#define MAXLOGSIZE 20000000
#define MAXLINSIZE 16000
#include <time.h>
#include <sys/timeb.h>
#include <stdarg.h>
char logfilename1[]="MyLog1.log";
char logfilename2[]="MyLog2.log";
static char logstr[MAXLINSIZE+1];
char datestr[16];
char timestr[16];
char mss[4];
CRITICAL_SECTION cs_log;
FILE *flog;
#ifdef _MSC_VER
void Lock(CRITICAL_SECTION *l) {
    EnterCriticalSection(l);
}
void Unlock(CRITICAL_SECTION *l) {
    LeaveCriticalSection(l);
}
void sleep_ms(int ms) {
    Sleep(ms);
}
#else
void Lock(CRITICAL_SECTION *l) {
    pthread_mutex_lock(l);
}
void Unlock(CRITICAL_SECTION *l) {
    pthread_mutex_unlock(l);
}
void sleep_ms(int ms) {
    usleep(ms*1000);
}
#endif
void LogV(const char *pszFmt,va_list argp) {
    struct tm *now;
    struct timeb tb;

    if (NULL==pszFmt||0==pszFmt[0]) return;
    vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);
    ftime(&tb);
    now=localtime(&tb.time);
    sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);
    sprintf(timestr,"%02d:%02d:%02d",now->tm_hour     ,now->tm_min  ,now->tm_sec );
    sprintf(mss,"%03d",tb.millitm);
    printf("%s %s.%s %s",datestr,timestr,mss,logstr);
    flog=fopen(logfilename1,"a");
    if (NULL!=flog) {
        fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);
        if (ftell(flog)>MAXLOGSIZE) {
            fclose(flog);
            if (rename(logfilename1,logfilename2)) {
                remove(logfilename2);
                rename(logfilename1,logfilename2);
            }
        } else {
            fclose(flog);
        }
    }
}
void Log(const char *pszFmt,...) {
    va_list argp;

    Lock(&cs_log);
    va_start(argp,pszFmt);
    LogV(pszFmt,argp);
    va_end(argp);
    Unlock(&cs_log);
}
//Log}
#define ASIZE    200
#define BSIZE    240
#define CSIZE      2
char Abuf[ASIZE];
char Cbuf[CSIZE];
CRITICAL_SECTION cs_HEX;
CRITICAL_SECTION cs_BBB;
struct FIFO_BUFFER {
    int  head;
    int  tail;
    int  size;
    char data[BSIZE];
} BBB;
int No_Loop=0;
void HexDump(int cn,char *buf,int len) {
    int i,j,k;
    char binstr[80];

    Lock(&cs_HEX);
    for (i=0;i<len;i++) {
        if (0==(i%16)) {
            sprintf(binstr,"%03d %04x -",cn,i);
            sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
        } else if (15==(i%16)) {
            sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
            sprintf(binstr,"%s  ",binstr);
            for (j=i-15;j<=i;j++) {
                sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');
            }
            Log("%s\n",binstr);
        } else {
            sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
        }
    }
    if (0!=(i%16)) {
        k=16-(i%16);
        for (j=0;j<k;j++) {
            sprintf(binstr,"%s   ",binstr);
        }
        sprintf(binstr,"%s  ",binstr);
        k=16-k;
        for (j=i-k;j<i;j++) {
            sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');
        }
        Log("%s\n",binstr);
    }
    Unlock(&cs_HEX);
}
int GetFromRBuf(int cn,CRITICAL_SECTION *cs,struct FIFO_BUFFER *fbuf,char *buf,int len) {
    int lent,len1,len2;

    lent=0;
    Lock(cs);
    if (fbuf->size>=len) {
        lent=len;
        if (fbuf->head+lent>BSIZE) {
            len1=BSIZE-fbuf->head;
            memcpy(buf     ,fbuf->data+fbuf->head,len1);
            len2=lent-len1;
            memcpy(buf+len1,fbuf->data           ,len2);
            fbuf->head=len2;
        } else {
            memcpy(buf     ,fbuf->data+fbuf->head,lent);
            fbuf->head+=lent;
        }
        fbuf->size-=lent;
    }
    Unlock(cs);
    return lent;
}
MYVOID thdB(void *pcn) {
    char        *recv_buf;
    int          recv_nbytes;
    int          cn;
    int          wc;
    int          pb;

    cn=(int)pcn;
    Log("%03d thdB              thread begin...\n",cn);
    while (1) {
        sleep_ms(10);
        recv_buf=(char *)Cbuf;
        recv_nbytes=CSIZE;
        wc=0;
        while (1) {
            pb=GetFromRBuf(cn,&cs_BBB,&BBB,recv_buf,recv_nbytes);
            if (pb) {
                Log("%03d recv %d bytes\n",cn,pb);
                HexDump(cn,recv_buf,pb);
                sleep_ms(1);
            } else {
                sleep_ms(1000);
            }
            if (No_Loop) break;//
            wc++;
            if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);
        }
        if (No_Loop) break;//
    }
#ifndef _MSC_VER
    pthread_exit(NULL);
#endif
}
int PutToRBuf(int cn,CRITICAL_SECTION *cs,struct FIFO_BUFFER *fbuf,char *buf,int len) {
    int lent,len1,len2;

    Lock(cs);
    lent=len;
    if (fbuf->size+lent>BSIZE) {
        lent=BSIZE-fbuf->size;
    }
    if (fbuf->tail+lent>BSIZE) {
        len1=BSIZE-fbuf->tail;
        memcpy(fbuf->data+fbuf->tail,buf     ,len1);
        len2=lent-len1;
        memcpy(fbuf->data           ,buf+len1,len2);
        fbuf->tail=len2;
    } else {
        memcpy(fbuf->data+fbuf->tail,buf     ,lent);
        fbuf->tail+=lent;
    }
    fbuf->size+=lent;
    Unlock(cs);
    return lent;
}
MYVOID thdA(void *pcn) {
    char        *send_buf;
    int          send_nbytes;
    int          cn;
    int          wc;
    int           a;
    int          pa;

    cn=(int)pcn;
    Log("%03d thdA              thread begin...\n",cn);
    a=0;
    while (1) {
        sleep_ms(100);
        memset(Abuf,a,ASIZE);
        a=(a+1)%256;
        if (16==a) {No_Loop=1;break;}//去掉这句可以让程序一直循环直到按Ctrl+C或Ctrl+Break或当前目录下存在文件No_Loop
        send_buf=(char *)Abuf;
        send_nbytes=ASIZE;
        Log("%03d sending %d bytes\n",cn,send_nbytes);
        HexDump(cn,send_buf,send_nbytes);
        wc=0;
        while (1) {
            pa=PutToRBuf(cn,&cs_BBB,&BBB,send_buf,send_nbytes);
            Log("%03d sent %d bytes\n",cn,pa);
            HexDump(cn,send_buf,pa);
            send_buf+=pa;
            send_nbytes-=pa;
            if (send_nbytes<=0) break;//
            sleep_ms(1000);
            if (No_Loop) break;//
            wc++;
            if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);
        }
        if (No_Loop) break;//
    }
#ifndef _MSC_VER
    pthread_exit(NULL);
#endif
}
int main() {
#ifdef _MSC_VER
    InitializeCriticalSection(&cs_log);
    InitializeCriticalSection(&cs_HEX);
    InitializeCriticalSection(&cs_BBB);
#else
    pthread_t threads[2];
    int threadsN;
    int rc;
    pthread_mutex_init(&cs_log,NULL);
    pthread_mutex_init(&cs_HEX,NULL);
    pthread_mutex_init(&cs_BBB,NULL);
#endif
    Log("Start===========================================================\n");

    BBB.head=0;
    BBB.tail=0;
    BBB.size=0;

#ifdef _MSC_VER
    _beginthread((void(__cdecl *)(void *))thdA,0,(void *)1);
    _beginthread((void(__cdecl *)(void *))thdB,0,(void *)2);
#else
    threadsN=0;
    rc=pthread_create(&(threads[threadsN++]),NULL,thdA,(void *)1);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1);
    rc=pthread_create(&(threads[threadsN++]),NULL,thdB,(void *)2);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1);
#endif

    if (!access("No_Loop",0)) {
        remove("No_Loop");
        if (!access("No_Loop",0)) {
            No_Loop=1;
        }
    }
    while (1) {
        sleep_ms(1000);
        if (No_Loop) break;//
        if (!access("No_Loop",0)) {
            No_Loop=1;
        }
    }
    sleep_ms(3000);
    Log("End=============================================================\n");
#ifdef _MSC_VER
    DeleteCriticalSection(&cs_BBB);
    DeleteCriticalSection(&cs_HEX);
    DeleteCriticalSection(&cs_log);
#else
    pthread_mutex_destroy(&cs_BBB);
    pthread_mutex_destroy(&cs_HEX);
    pthread_mutex_destroy(&cs_log);
#endif
    return 0;
}
任何收发两端速度不一致的通讯,都需要在它们之间使用一个足够大的FIFO缓冲区。 对任何FIFO缓冲区的使用,都需要仔细考虑接收端接收时超时无数据和发送端发送时FIFO缓冲区已满这两种情况下该如何做。 这些概念都在这段经典代码中有所体现。 这段经典代码还包括以下必须考虑的因素: ◆跨Windows和Linux平台 ◆多线程锁 ◆多线程日志 ◆日志文件占用的磁盘空间可控 ◆日志中的时间包括毫秒 ◆传输的数据对应的每个字节到底是几 ◆如何退出多线程程序 ◆……
赵4老师 2017-02-21
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
Pingo520 2017-02-21
  • 打赏
  • 举报
回复
引用 5 楼 shenyi0106 的回复:
你一次发100个字节的数据出去,你接收的时候,不见得就是一次能收到100个字节,可能会分成1+99,也可能是40+60等等,各种你想不到的组合,所以最好还是在OnReceive中读取数据,不要做业务处理
我上面的代码是在OnReceive里面读取数据的,我的数据包格式是包头加+长度,解析出长度,然后接收一整个完整的包,再把这个包房到线程池去处理。你帮忙看下我那个代码。我现在运行的代码把data数组改成1024,接收的试试Receive(data,1024),其他的没变,然后传指针到线程,在线程里面对申请的内存进行释放,现在发现有内存泄漏。
shenyi0106 2017-02-21
  • 打赏
  • 举报
回复
你一次发100个字节的数据出去,你接收的时候,不见得就是一次能收到100个字节,可能会分成1+99,也可能是40+60等等,各种你想不到的组合,所以最好还是在OnReceive中读取数据,不要做业务处理
Pingo520 2017-02-21
  • 打赏
  • 举报
回复
引用 1 楼 shenyi0106 的回复:
缓冲区已经被塞满了,不能再出发FD_READ事件了 在OnReceive中的的正确做法是:一直读,读到返回0(或者-1)为止
刚我把接收缓冲区data大小改成1024,然后按你说的这么做,就没再出现这种情况了,可能真是缓冲区被塞满的原因,再调试看看。 有没有其他问题。帮我看看这代码有没有其他问题啊,特别是那个动态数组的释放。
Pingo520 2017-02-21
  • 打赏
  • 举报
回复
在线等
Pingo520 2017-02-21
  • 打赏
  • 举报
回复
引用 1 楼 shenyi0106 的回复:
缓冲区已经被塞满了,不能再出发FD_READ事件了 在OnReceive中的的正确做法是:一直读,读到返回0(或者-1)为止
应该不会塞满吧,我是发一次,每次发都是一个整包,然后执行读,每次都是一个整包整包的读取,也就是说每次都读完的。 难道我把里面的数据都读出来了,缓冲区的数据还在?
shenyi0106 2017-02-21
  • 打赏
  • 举报
回复
缓冲区已经被塞满了,不能再出发FD_READ事件了 在OnReceive中的的正确做法是:一直读,读到返回0(或者-1)为止
Pingo520 2017-02-21
  • 打赏
  • 举报
回复
引用 10 楼 oyljerry 的回复:
主要是你不能期望OnReceive中能够一次就把这次发送的数据接收完成,你需要复制到到一个地方,然后让OnReiceive继续接收处理后面的数据,而你代码自己来判断所有接收的数据是否完成了,才开始后面的数据内容处理
结合你说的和赵老师的例子,你看我下面的想法对不对。 (我这写的是服务端,暂时只考虑接收数据。) 1、每来一个客户端连接,就单独开一个缓冲区存放接收到的数据,设好头和尾。 2、开一个工作线程处理这个连接的数据。 3、OnReceive每次收到数据就往缓冲区里面丢,添加到缓冲区尾,当缓冲区满的时候就考虑丢掉这部分数据或者覆盖一部分缓冲区。 3、当缓冲区有数据的时候,工作线程就从缓冲区里面取数据处理,重置头和尾。 上面的方案如果连接很多,就要开很多工作线程,且要申请很多缓冲区,连接不断开,这些资源就一直在占用着,这是我担心的。
赵4老师 2017-02-21
  • 打赏
  • 举报
回复
基本理解正确。
oyljerry 2017-02-21
  • 打赏
  • 举报
回复
主要是你不能期望OnReceive中能够一次就把这次发送的数据接收完成,你需要复制到到一个地方,然后让OnReiceive继续接收处理后面的数据,而你代码自己来判断所有接收的数据是否完成了,才开始后面的数据内容处理
Pingo520 2017-02-21
  • 打赏
  • 举报
回复
引用 8 楼 zhao4zhong1 的回复:
仅供参考:
//循环向a函数每次发送200个字节长度(这个是固定的)的buffer,
//a函数中需要将循环传进来的buffer,组成240字节(也是固定的)的新buffer进行处理,
//在处理的时候每次从新buffer中取两个字节打印
#ifdef _MSC_VER
    #pragma warning(disable:4996)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
    #include <windows.h>
    #include <process.h>
    #include <io.h>
    #define  MYVOID             void
    #define  vsnprintf          _vsnprintf
#else
    #include <unistd.h>
    #include <sys/time.h>
    #include <pthread.h>
    #define  CRITICAL_SECTION   pthread_mutex_t
    #define  MYVOID             void *
#endif
//Log{
#define MAXLOGSIZE 20000000
#define MAXLINSIZE 16000
#include <time.h>
#include <sys/timeb.h>
#include <stdarg.h>
char logfilename1[]="MyLog1.log";
char logfilename2[]="MyLog2.log";
static char logstr[MAXLINSIZE+1];
char datestr[16];
char timestr[16];
char mss[4];
CRITICAL_SECTION cs_log;
FILE *flog;
#ifdef _MSC_VER
void Lock(CRITICAL_SECTION *l) {
    EnterCriticalSection(l);
}
void Unlock(CRITICAL_SECTION *l) {
    LeaveCriticalSection(l);
}
void sleep_ms(int ms) {
    Sleep(ms);
}
#else
void Lock(CRITICAL_SECTION *l) {
    pthread_mutex_lock(l);
}
void Unlock(CRITICAL_SECTION *l) {
    pthread_mutex_unlock(l);
}
void sleep_ms(int ms) {
    usleep(ms*1000);
}
#endif
void LogV(const char *pszFmt,va_list argp) {
    struct tm *now;
    struct timeb tb;

    if (NULL==pszFmt||0==pszFmt[0]) return;
    vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);
    ftime(&tb);
    now=localtime(&tb.time);
    sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);
    sprintf(timestr,"%02d:%02d:%02d",now->tm_hour     ,now->tm_min  ,now->tm_sec );
    sprintf(mss,"%03d",tb.millitm);
    printf("%s %s.%s %s",datestr,timestr,mss,logstr);
    flog=fopen(logfilename1,"a");
    if (NULL!=flog) {
        fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);
        if (ftell(flog)>MAXLOGSIZE) {
            fclose(flog);
            if (rename(logfilename1,logfilename2)) {
                remove(logfilename2);
                rename(logfilename1,logfilename2);
            }
        } else {
            fclose(flog);
        }
    }
}
void Log(const char *pszFmt,...) {
    va_list argp;

    Lock(&cs_log);
    va_start(argp,pszFmt);
    LogV(pszFmt,argp);
    va_end(argp);
    Unlock(&cs_log);
}
//Log}
#define ASIZE    200
#define BSIZE    240
#define CSIZE      2
char Abuf[ASIZE];
char Cbuf[CSIZE];
CRITICAL_SECTION cs_HEX;
CRITICAL_SECTION cs_BBB;
struct FIFO_BUFFER {
    int  head;
    int  tail;
    int  size;
    char data[BSIZE];
} BBB;
int No_Loop=0;
void HexDump(int cn,char *buf,int len) {
    int i,j,k;
    char binstr[80];

    Lock(&cs_HEX);
    for (i=0;i<len;i++) {
        if (0==(i%16)) {
            sprintf(binstr,"%03d %04x -",cn,i);
            sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
        } else if (15==(i%16)) {
            sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
            sprintf(binstr,"%s  ",binstr);
            for (j=i-15;j<=i;j++) {
                sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');
            }
            Log("%s\n",binstr);
        } else {
            sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
        }
    }
    if (0!=(i%16)) {
        k=16-(i%16);
        for (j=0;j<k;j++) {
            sprintf(binstr,"%s   ",binstr);
        }
        sprintf(binstr,"%s  ",binstr);
        k=16-k;
        for (j=i-k;j<i;j++) {
            sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');
        }
        Log("%s\n",binstr);
    }
    Unlock(&cs_HEX);
}
int GetFromRBuf(int cn,CRITICAL_SECTION *cs,struct FIFO_BUFFER *fbuf,char *buf,int len) {
    int lent,len1,len2;

    lent=0;
    Lock(cs);
    if (fbuf->size>=len) {
        lent=len;
        if (fbuf->head+lent>BSIZE) {
            len1=BSIZE-fbuf->head;
            memcpy(buf     ,fbuf->data+fbuf->head,len1);
            len2=lent-len1;
            memcpy(buf+len1,fbuf->data           ,len2);
            fbuf->head=len2;
        } else {
            memcpy(buf     ,fbuf->data+fbuf->head,lent);
            fbuf->head+=lent;
        }
        fbuf->size-=lent;
    }
    Unlock(cs);
    return lent;
}
MYVOID thdB(void *pcn) {
    char        *recv_buf;
    int          recv_nbytes;
    int          cn;
    int          wc;
    int          pb;

    cn=(int)pcn;
    Log("%03d thdB              thread begin...\n",cn);
    while (1) {
        sleep_ms(10);
        recv_buf=(char *)Cbuf;
        recv_nbytes=CSIZE;
        wc=0;
        while (1) {
            pb=GetFromRBuf(cn,&cs_BBB,&BBB,recv_buf,recv_nbytes);
            if (pb) {
                Log("%03d recv %d bytes\n",cn,pb);
                HexDump(cn,recv_buf,pb);
                sleep_ms(1);
            } else {
                sleep_ms(1000);
            }
            if (No_Loop) break;//
            wc++;
            if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);
        }
        if (No_Loop) break;//
    }
#ifndef _MSC_VER
    pthread_exit(NULL);
#endif
}
int PutToRBuf(int cn,CRITICAL_SECTION *cs,struct FIFO_BUFFER *fbuf,char *buf,int len) {
    int lent,len1,len2;

    Lock(cs);
    lent=len;
    if (fbuf->size+lent>BSIZE) {
        lent=BSIZE-fbuf->size;
    }
    if (fbuf->tail+lent>BSIZE) {
        len1=BSIZE-fbuf->tail;
        memcpy(fbuf->data+fbuf->tail,buf     ,len1);
        len2=lent-len1;
        memcpy(fbuf->data           ,buf+len1,len2);
        fbuf->tail=len2;
    } else {
        memcpy(fbuf->data+fbuf->tail,buf     ,lent);
        fbuf->tail+=lent;
    }
    fbuf->size+=lent;
    Unlock(cs);
    return lent;
}
MYVOID thdA(void *pcn) {
    char        *send_buf;
    int          send_nbytes;
    int          cn;
    int          wc;
    int           a;
    int          pa;

    cn=(int)pcn;
    Log("%03d thdA              thread begin...\n",cn);
    a=0;
    while (1) {
        sleep_ms(100);
        memset(Abuf,a,ASIZE);
        a=(a+1)%256;
        if (16==a) {No_Loop=1;break;}//去掉这句可以让程序一直循环直到按Ctrl+C或Ctrl+Break或当前目录下存在文件No_Loop
        send_buf=(char *)Abuf;
        send_nbytes=ASIZE;
        Log("%03d sending %d bytes\n",cn,send_nbytes);
        HexDump(cn,send_buf,send_nbytes);
        wc=0;
        while (1) {
            pa=PutToRBuf(cn,&cs_BBB,&BBB,send_buf,send_nbytes);
            Log("%03d sent %d bytes\n",cn,pa);
            HexDump(cn,send_buf,pa);
            send_buf+=pa;
            send_nbytes-=pa;
            if (send_nbytes<=0) break;//
            sleep_ms(1000);
            if (No_Loop) break;//
            wc++;
            if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);
        }
        if (No_Loop) break;//
    }
#ifndef _MSC_VER
    pthread_exit(NULL);
#endif
}
int main() {
#ifdef _MSC_VER
    InitializeCriticalSection(&cs_log);
    InitializeCriticalSection(&cs_HEX);
    InitializeCriticalSection(&cs_BBB);
#else
    pthread_t threads[2];
    int threadsN;
    int rc;
    pthread_mutex_init(&cs_log,NULL);
    pthread_mutex_init(&cs_HEX,NULL);
    pthread_mutex_init(&cs_BBB,NULL);
#endif
    Log("Start===========================================================\n");

    BBB.head=0;
    BBB.tail=0;
    BBB.size=0;

#ifdef _MSC_VER
    _beginthread((void(__cdecl *)(void *))thdA,0,(void *)1);
    _beginthread((void(__cdecl *)(void *))thdB,0,(void *)2);
#else
    threadsN=0;
    rc=pthread_create(&(threads[threadsN++]),NULL,thdA,(void *)1);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1);
    rc=pthread_create(&(threads[threadsN++]),NULL,thdB,(void *)2);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1);
#endif

    if (!access("No_Loop",0)) {
        remove("No_Loop");
        if (!access("No_Loop",0)) {
            No_Loop=1;
        }
    }
    while (1) {
        sleep_ms(1000);
        if (No_Loop) break;//
        if (!access("No_Loop",0)) {
            No_Loop=1;
        }
    }
    sleep_ms(3000);
    Log("End=============================================================\n");
#ifdef _MSC_VER
    DeleteCriticalSection(&cs_BBB);
    DeleteCriticalSection(&cs_HEX);
    DeleteCriticalSection(&cs_log);
#else
    pthread_mutex_destroy(&cs_BBB);
    pthread_mutex_destroy(&cs_HEX);
    pthread_mutex_destroy(&cs_log);
#endif
    return 0;
}
任何收发两端速度不一致的通讯,都需要在它们之间使用一个足够大的FIFO缓冲区。 对任何FIFO缓冲区的使用,都需要仔细考虑接收端接收时超时无数据和发送端发送时FIFO缓冲区已满这两种情况下该如何做。 这些概念都在这段经典代码中有所体现。 这段经典代码还包括以下必须考虑的因素: ◆跨Windows和Linux平台 ◆多线程锁 ◆多线程日志 ◆日志文件占用的磁盘空间可控 ◆日志中的时间包括毫秒 ◆传输的数据对应的每个字节到底是几 ◆如何退出多线程程序 ◆……
意思是我这里应该自己为每一个连接维护一个缓冲区,每接收到一个数据包就丢往缓冲区,如果缓冲区有数据,再用逻辑处理线程去缓冲区取数据,而不是在接收线程里临时new内存,然后再释放,这样容易造成内存碎片,对吗。当然,这里要考虑到线程同步问题。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧