在伺服器客戶端通訊的時候,並不是像簡單的echo伺服器那樣,還是傳送特定的資料報協議。
資料報的協議可以用自定義結構體定義。
自定義協議分簡單分為訊息頭, 和內容,訊息頭具有訊息的長度,和型別,使用繼承的方法,簡單實現
#ifndef _messageheader_hpp_
#define _messageheader_hpp_
enum cmd
;struct dataheader
;//datapackage
struct login : public dataheader
char username[32];
char password[32];
};struct loginresult : public dataheader
int result;
char data[1024];
};struct logout : public dataheader
char username[32];
};struct logoutresult : public dataheader
int result;
};struct newuserjoin : public dataheader
int scok;
};#endif // !_messageheader_hpp_
伺服器使用c++ 物件導向的方式封裝,主函式**只有以下幾行,很好理解
#include "easytcpserver.hpp"
int main()
server.close();
printf("已退出。\n");
getchar();
return 0;
}
easytcpserver這個類封裝了 伺服器的基本設定函式,同時使用了乙個stl vector陣列來儲存連線的客戶端
class easytcpserver
這裡最重要的邏輯函式是
每次呼叫select函式之前,都要重新設定fd_set
bool onrun()
}///nfds 是乙個整數值 是指fd_set集合中所有描述符(socket)的範圍,而不是數量
///既是所有檔案描述符最大值+1 在windows中這個引數可以寫0
//timeval t = ;
int ret = select(maxsock + 1, &fdread, &fdwrite, &fdexp, nullptr); //&t
//printf("select ret=%d count=%d\n", ret, _ncount++);
if (ret < 0)
//判斷描述符(socket)是否在集合中
if (fd_isset(_sock, &fdread))
for (int n = (int)g_clients.size() - 1; n >= 0; n--)}}
}return true;
} return false;
}
其中recvdata函式的實現也特別關鍵
一次讀取 1024 * 400 = 400k資料,再拆分處理
//緩衝區
char szrecv[409600] = {};
//接收資料 處理粘包 拆分包
int recvdata(socket _csock)
loginresult ret;
senddata(_csock, &ret);
/*dataheader* header = (dataheader*)szrecv;
recv(_csock, szrecv + sizeof(dataheader), header->datalength - sizeof(dataheader), 0);
onnetmsg(_csock, header);
*/return 0;
}
伺服器回送請求
//響應網路訊息
virtual void onnetmsg(socket _csock, dataheader* header)
break;
case cmd_logout:
break;
default:
; send(_csock, (char*)&header, sizeof(header), 0);
} break;
} }
客戶端的實現比較簡單, 開一線程用來接受命令,退出
#include "easytcpclient.hpp"
#includevoid cmdthread(easytcpclient* client)
; scanf("%s", cmdbuf);
if (0 == strcmp(cmdbuf, "exit"))
else if (0 == strcmp(cmdbuf, "login"))
else if (0 == strcmp(cmdbuf, "logout"))
else }}
int main()
client1.close();
printf("已退出。\n");
getchar();
return 0;
}
客戶端也是用select接受資料
//處理網路訊息
int _ncount = 0;
bool onrun()
; int ret = select(_sock + 1, &fdreads, 0, 0, &t);
//printf("select ret=%d count=%d\n", ret, _ncount++);
if (ret < 0)
if (fd_isset(_sock, &fdreads))
}return true;
} return false;
}
這裡接受訊息包括了粘包的處理
//處理網路訊息
int _ncount = 0;
bool onrun()
; int ret = select(_sock + 1, &fdreads, 0, 0, &t);
//printf("select ret=%d count=%d\n", ret, _ncount++);
if (ret < 0)
if (fd_isset(_sock, &fdreads))
}return true;
} return false;
}
自定義Redis快取伺服器
mybatis的快取機制 一級快取 sqlsession mybatis的資料庫連線 級別的快取 預設開啟,直接可以使用 對開發沒有任何意義 資料庫連線close,快取也消失 二級快取 sqlsessionfactory mybatis的資料庫連線工廠 級別的快取 預設關閉,需要手動開啟 在myba...
自定義伺服器控制項ImageButton
在日常專案開發中,我們會經常用到自定義控制項,我們通過乙個簡單的例子來說明,在日常專案中我們經常會用到,或者控制項,我們以imagebutton為例來說明。imgbtn runat server imageurl images add.png 很多時候我們需要在很多頁面上放上面這段 每次都要重複設定...
自定義伺服器控制項ImageButton
在日常專案開發中,我們會經常用到自定義控制項,我們通過乙個簡單的例子來說明,在日常專案中我們經常會用到,或者控制項,我們以imagebutton為例來說明。imgbtn runat server imageurl images add.png 很多時候我們需要在很多頁面上放上面這段 每次都要重複設定...