EasyTCP 伺服器簡單自定義協議程式設計

2021-09-25 02:33:56 字數 3400 閱讀 6384

在伺服器客戶端通訊的時候,並不是像簡單的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 很多時候我們需要在很多頁面上放上面這段 每次都要重複設定...