TCP多執行緒服務器,一個執行緒監聽,來一個連接就起一個執行緒處理。行程中有兩個這樣的服務器,監聽不同的埠,埠A來的是長連接,埠B除了一個長連接之外,還接受每10秒2個的短連接。
連續正常運行20多天后(故障報上來的時候是28天多一點),telnet埠B失敗,connect也失敗。但埠B上的長連接作業正常(資料一直在走),埠A也正常,可以telnet,也可以connect。(兩個TCP服務器是相同的代碼,兩個實體而已,唯一的區別就是監聽埠不同,且埠B上多了每10秒2個的短連接)。
重啟行程后(未重啟作業系統),故障消除。重啟前觀察到:
埠B處于listening狀態,netstat無TIME_WAIT的socket及其他例外連接;
作業系統的句柄數量正常(5k左右,與重啟后一致);
CPU負荷正常(4%左右,與重啟后一致)
補充:
作業系統是WindowsXP;
短連接客戶端未主動斷開,而是被服務器超時檢查斷開;
程式日志默認未開啟埠B的連接日志記錄(量太大)。此時若打開日志,需要重啟行程才生效,就不知道要等多久才能抓到了;
另外,這個程式運行在幾十臺相同平臺上,目前有兩臺出現這個問題(其中一臺已經重啟行程,另一臺未重啟,故障依然),其他的暫正常。
請大家幫忙看看,問題可能出在哪兒,還需要檢查些什么(還有一臺還沒重啟行程)。
uj5u.com熱心網友回復:
1、記憶體泄漏,這個估計可能性小些2、執行緒死鎖,看你的說法一個連接一個執行緒,應該是有連接斷掉后執行緒沒有釋放,到一定程度開不出新執行緒了,我感覺這個可能性比較大
uj5u.com熱心網友回復:
但是埠B無法連接的同時,埠A卻可以連上去并正常作業啊。uj5u.com熱心網友回復:
那可以試下一下A埠也開一個短連接,是否出現同樣的問題,如果是那可能搶占資源了uj5u.com熱心網友回復:
同意,感覺比較像死鎖的問題。
樓主可以嘗試寫個模擬客戶端連接demo,多連接和斷開連接。
鎖的話建議使用物件析構自動釋放鎖會比較好些,這樣不會產生死鎖問題,lock_guard
uj5u.com熱心網友回復:
加監控服務, 如果例外重啟服務, 或者定時重啟, 比如每天凌晨3點重啟能找到問題當然更好
uj5u.com熱心網友回復:
從現象上看,connect不能回傳,肯定是服務端Accept沒有呼叫導致的,而你的實作邏輯是將Accept放在一個執行緒中回圈呼叫,
根據你的實作邏輯判斷,能夠導致Accept停止呼叫的原因無外乎Accept執行緒死鎖 或者 Accept執行緒退出了。
Accept執行緒死鎖,應該是你的代碼有問題,請檢查你自己的代碼,我們沒有代碼,不好給出參考意見;
Accept執行緒退出,我個人覺得這個可能性很大,請檢查Accept執行緒中所有API的回傳值,以及所有的針對回傳值的判斷陳述句,是不是將該寫continue的地方寫成了return?
另外,日志系統也應該健壯起來,應該給你的日志系統分級,像錯誤(Error)級別的日志,應該實時輸出,這有助于你發現問題
uj5u.com熱心網友回復:
檢查是否資源泄漏的辦法之一:在任務管理器 行程 查看 選擇列 里面選擇:記憶體使用、虛擬記憶體大小、句柄數、執行緒數、USER物件、GDI物件
讓你的程式(行程)不退出,回圈執行主流程很多遍,越多越好,比如1000000次甚至無限回圈,記錄以上各數值,再隔至少一小時,越長越好,比如一個月,再記錄以上各數值。如果以上兩組數值的差較大或隨時間流逝不斷增加,則鐵定有對應資源的資源泄漏!
搜“GDI泄露檢測”?
有時不將“呼叫函式名字+各引數值,進入函式后各引數值,中間變數值,退出函式前準備回傳的值,回傳函式到呼叫處后函式名字+各引數值+回傳值”這些資訊寫日志到檔案中是無論如何也發現不了問題在哪里的,包括捕獲各種例外、寫日志到螢屏、單步或設斷點或生成core或dmp檔案、……這些方法都不行! 寫日志到檔案參考下面:
//回圈向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;
}
uj5u.com熱心網友回復:
謝謝各位。關于日志:
主要還是以前懶了一下,將日志級別修改寫成了冷配,即修改之后要重啟才生效。埠A的連接失敗資訊有記錄日志,但埠B由于會有很多短連接,而且均是超時關閉,所以就做了個選項,打開之后才記日志,而該選項默認是關掉的。現在如果打開該日志選項,需要重啟行程,而重啟后故障就沒了,等下一次故障不知道要等到什么時候了。
另外,我大概看了一下其他沒有問題的機器,有的已經連續運行40多天了,其記憶體占用、句柄數量、執行緒數量等與有問題那臺基本一致。——這些機器的軟硬體環境完全一樣。
剛才試了一下,連上去故障碼是10061:由于目標機器積極拒絕,無法連接。本地也無法telnet進去。
完全沒有頭緒。接下來準備將有故障那臺恢復掉,然后在本地進行一個大量長期短連接測驗,希望可以重現。
uj5u.com熱心網友回復:
除了多分析日志等,還可以用除錯工具attach到行程上,然后看看當前行程的一些運行狀態資訊等來分析。uj5u.com熱心網友回復:
服務器代碼未變,運行在win2003上,用以下客戶端代碼測驗(在另外一臺Win7上跑),已經連了14W次(大約相當與正常情況下3天的量)了,沒出狀況,還在繼續:volatile long ct=0;
volatile long trd=0;
UINT __stdcall _trd(void* param)
{
InterlockedIncrement(&trd);
linger li;
li.l_onoff=1;
li.l_linger=0;
while(1)
{
InterlockedIncrement(&ct);
wFSockBase wt;
s32 r=wt.Connect(715,"172.18.6.1");
if(0!=r){
printf("\t!!Connect FAILED,count=%u,err=%d\n",ct,r); //共3個執行緒,其中兩個中間報10061退出了,剩一個還在繼續跑。這個10061是不是因為服務器listen的backlog已滿?
break;
}
if(0!=setsockopt(wt.getHandle(),SOL_SOCKET,SO_LINGER,(const char*)&li,sizeof(li))){ //避免客戶端TIME_WAIT導致無法繼續
printf("set linger failed:%d\n",WSAGetLastError());
break;
}
wt.Close();
}
InterlockedDecrement(&trd);
return 0;
}
int main(int argc, char* argv[])
{
wSockEnv::InitSock(3000);
for(u32 i=0;i<3;i++)_beginthreadex(NULL,0,_trd,NULL,0,NULL);
Sleep(1000);
while(trd>0){
printf("count=%d\n",ct);
Sleep(1000);
}
printf("all thread complete.ct=%d\n",ct);
system("pause");
return 0;
}
uj5u.com熱心網友回復:
現在20W了,相當于4天的量。重貼一下測驗客戶端代碼:volatile long ct=0;
volatile long trd=0;
UINT __stdcall _trd(void* param)
{
InterlockedIncrement(&trd);
linger li;
li.l_onoff=1;
li.l_linger=0;
while(1)
{
InterlockedIncrement(&ct);
wFSockBase wt; //簡單的socket封裝
s32 r=wt.Connect(715,"172.18.6.1"); //先轉為非阻塞,select判斷連接,以便超時,超時值為3秒,在主執行緒內設定
if(0!=r){
printf("\t!!Connect FAILED,count=%u,err=%d\n",ct,r);
break;
}
if(0!=setsockopt(wt.getHandle(),SOL_SOCKET,SO_LINGER,(const char*)&li,sizeof(li))){//避免TIME_WAIT
printf("set linger failed:%d\n",WSAGetLastError());
break;
}
wt.Close();
}
InterlockedDecrement(&trd);
return 0;
}
int main(int argc, char* argv[])
{
wSockEnv::InitSock(3000); //初始化環境,設定連接超時時間為3秒
for(u32 i=0;i<3;i++)_beginthreadex(NULL,0,_trd,NULL,0,NULL);
Sleep(1000);
while(trd>0){
printf("count=%d\n",ct);
Sleep(1000);
}
printf("all thread complete.ct=%d\n",ct);
system("pause");
return 0;
}
uj5u.com熱心網友回復:
有句柄未關閉情況。檢查代碼吧,打上日志,看看是不是accept不了。uj5u.com熱心網友回復:
還在測?把客戶端都停下來一段時間(超過你的心跳檢測間隔),看看服務程式的執行緒數是否恢復了uj5u.com熱心網友回復:
悲劇了。測了一個晚上(現在還在跑),短連接數量已經超過600W了。這個數量與出故障的機器相比,已經相當于連續運行一年的數量了,一切正常:作業系統記憶體、句柄、負荷占用均正常,行程的記憶體、句柄、負荷也正常。行程的所有功能也正常。
測驗環境與作業環境的差異就是作業系統了。測驗環境是WIndows2003,作業環境是WIndowsXP。
但有一個情況值得重視,就是測驗程式的3個執行緒,其中有兩個很早就報10061,然后退出了,剩下一個執行緒一直跑到現在。
綜合看起來,基本可以排除資源(記憶體、句柄等)泄漏和死鎖的問題,行程的執行緒數量也符合預期。
打算先搞明白測驗環境的兩個10061的原因。有點懷疑是listen的backlog佇列滿導致。
各位大俠看看,還有什么思路。
uj5u.com熱心網友回復:
理一下:1 故障時,除了埠B不接受新的連接之外,其他一切正常,包括接受連接,創建新執行緒等。這基本可排除句柄泄漏,包括套接字句柄、執行緒句柄等。
2 除了在創建客戶端執行緒時臨時申請幾個位元組的執行緒引數所用記憶體外,其余記憶體均為在啟動時一次性申請,運行中不動態申請。考慮到目前測驗和現場情況,基本排除記憶體泄漏。
3 記憶體溢位。無完全排除,但可能性極小。
目前考慮以下可能:
1 埠B上的accept執行緒,不知何故掛起或退出了。這個與現象最吻合,但目前沒找到辦法重現,回頭再仔細看看代碼;
2 埠B上的半開連接過多,導致backlog滿,而無法接收連接,就像測驗環境下出現的10061。這個還有辦法搞搞。但這個與故障現象不完全符合,因為過一會就可以連了,而現場是一直連不上。
如果一直找不到原因的話,目前暫時考慮的處理方法:
1 將listen的backlog加大;
2 將作業系統重新做一下;
3 如果實在不行,最后只有祭出終極大發:定時重啟服務——實在不愿意這么做。
uj5u.com熱心網友回復:
如果最大連接數不大的話,建議執行緒先創建好了,有連接進來,再分配一個執行緒服務它。FTPFileZilla的原始碼就是這么做的。
執行緒的創建和銷毀,如果操作不當,會產生資源泄露的。
uj5u.com熱心網友回復:
最初是按客戶端使用長連接來設計的,所以就懶了一下沒用執行緒池。哪知道后來客戶端會使用短連接。另外,執行緒的創建和銷毀目前看起來應該不存在資源泄漏,原因是當埠B不能連接時,埠A是可以正常連接并創建新執行緒提供服務的。
uj5u.com熱心網友回復:
早晚要池化所有資源,包括執行緒。老司機找bug的十年心路歷程:http://blog.csdn.net/zhao4zhong1/article/details/53078924
uj5u.com熱心網友回復:
連不上時在服務器上執行命令netstat -na看一下?uj5u.com熱心網友回復:
看過了。沒有例外。沒有TIME_WAIT等,埠也處于LISTENING狀態
uj5u.com熱心網友回復:
問題的根源應該是記憶體沒有正確釋放。長鏈接的資源一直有效,所以能正常運行,新進的鏈接由于申請不到資源,所以鏈接失敗
uj5u.com熱心網友回復:
莫非是智能路由器上有攔截功能
或者
遭arp劫持
?
uj5u.com熱心網友回復:
說不定是硬體問題呢!
uj5u.com熱心網友回復:
感覺不像。故障時埠A是可以正常連接的。
uj5u.com熱心網友回復:
這個也應該不是。在本地TELNET也無法連接埠B。
uj5u.com熱心網友回復:
不排除作業系統有問題。所以打算恢復新的作業系統鏡像看看,不過周期會比較長,也很難得出明確的結論。
uj5u.com熱心網友回復:
有些作業系統跑的很好,另外一個操作出問題也是有可能的。樓主如果是win7的,可以在xp下跑,或者win10上跑試試。
uj5u.com熱心網友回復:
xp的TCP補丁打了嗎?默認的我記得只有10吧!!沒打快去打!
uj5u.com熱心網友回復:
服務器有沒有定時處理一些事務的函式,如果有,重點檢查一下,尤其要注意公用變數。uj5u.com熱心網友回復:
從lz的描述,大膽猜測一下, 應該是短鏈接的邏輯, 影響到了accept
至于短鏈接 為什么 影響到accept : 可以從以下幾個方面 逐一排查
1:lz提到telnet也失敗, lz可以首先確認一下,如果在服務器本機直接telnet本機埠b,看是否同樣失敗
2:lz提到沒有TIME_WAIT,但是有沒有出現大量SYN_RECV呢?,即是否有大量鏈接處于半開鏈接的狀態呢,半開連接數達到最大限制,也會導致丟棄后續的TCP連接請求。
3:直接在服務器上開抓包工具,然后在其他電腦上去telnet埠b,看tcp三次握手到哪一步:埠b是否收到了第一次握手的SYN?埠b是否識訓復了SYN+ACK?埠b是否收到第三次握手的ACK?鏈接建立不起來,應該是3次握手未完成
uj5u.com熱心網友回復:
樓上說抓包是個好主意在服務器上安個抓包工具 sniffer
uj5u.com熱心網友回復:
說得中uj5u.com熱心網友回復:
1.不應該來一個連接請求就開一個執行緒,你可以測驗一下,單行程內,可以開的執行緒數量是有限的,因此如果外部一直連接而不斷開,后面的就再也連接不上了。應該用其它I/O模型,比如IOCP,你現在用的方式應該是性能最差的一種
2.你現在測驗的連接幾百萬次,應該是連接上就斷開的方式吧,并沒有保持在一定時間內或進行長時間資料傳輸測驗,有可能如樓上面幾位說的,在接識訓發送資料時,資源沒有完全釋放,導致執行緒退不出去,耗盡了執行緒方面的資源
uj5u.com熱心網友回復:
學習一下,謝謝!!!uj5u.com熱心網友回復:
執行緒開多了,調度占用資源uj5u.com熱心網友回復:
對,執行緒的切換,CPU開銷很大
uj5u.com熱心網友回復:
懷疑是XP下半開連接數默認設定過小的問題,迅雷好像有類似的選項可以進行設定,也可以搜索下專門的工具。見https://zhidao.baidu.com/question/544738895.html
uj5u.com熱心網友回復:
謝謝!
1 服務器本地telnet埠B也失敗,回傳10061,就跟埠沒開一樣;
2 netstat -na既沒有TIME_WAIT,也沒有SYN_RECV等
3 這個可惜了,當時因為要恢復運行,就沒有做這個就重啟程式了。
程式重啟到現在,一直都正常。
uj5u.com熱心網友回復:
謝謝!
但感覺應該不是這個問題:
1 故障時,程式執行緒數為8,是正確的值(包括accept的執行緒);
2 故障時,埠A無法連接,但埠B卻可以連接,而且可以回應與埠B完全一樣的互動,包括創建執行緒,計算,接收發送資料等。(埠A與埠B上運行的同一個TCP服務器class的實體,唯一區別就是監聽埠不同)
uj5u.com熱心網友回復:
最早也是懷疑這個,因為還有大概100多太Win7也在運行這個程式,沒有見到上報這個錯誤。
但是,netstat -na沒看到任何例外啊?
uj5u.com熱心網友回復:
學習一下,謝謝!!!uj5u.com熱心網友回復:
最近想到一個可能,請大家看看有沒有可能:由于監聽套接字設定了埠服務復用。如果在程式運行程序中,另外一個行程M運行起來,也監聽在埠B上,并且也設定了埠復用,之后這個行程M退出了,那會不會導致現在的情況?
最近在忙別的事情,等有空了測一下這種情況。
uj5u.com熱心網友回復:
我猜大概率的應該是accept佇列滿了(具體是不是可能需要看抓包情況),
而accept佇列滿,則說明,你的服務器程式里面,負責accept的那個執行緒出問題了,或者是死鎖了,導致程式不再從accept佇列取出已經建立完成的鏈接,
至于accept執行緒為什么出問題, 就要查代碼了
uj5u.com熱心網友回復:
有時不將“呼叫函式名字+各引數值,進入函式后各引數值,中間變數值,退出函式前準備回傳的值,回傳函式到呼叫處后函式名字+各引數值+回傳值”這些資訊寫日志到檔案中是無論如何也發現不了問題在哪里的,包括捕獲各種例外、寫日志到螢屏、單步或設斷點或生成core或dmp檔案、……這些方法都不行! 寫日志到檔案參考下面://回圈向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;
}
uj5u.com熱心網友回復:
樓主的問題后來解決了?uj5u.com熱心網友回復:
樓主 說說這個問題怎么樣了uj5u.com熱心網友回復:
tcp有連接數限制 半開連接數限制。注冊表里讀取 找個工具查看下。轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/81900.html
標籤:網絡編程
上一篇:有關過完備DCT字典的問題
