int make_server_socket(int port);//1 void handleAccept(int socket_fd);//2 int main(int ac, char *av[]) { int tcp_socket = make_server_socket(8888); if (tcp_socket == -1) { exit(0); } thread t;//3 while (1) { int socket_fd = accept(tcp_socket, nullptr, nullptr); //4 t = thread(handleAccept, socket_fd);//3 t.detach();//3 } system("pause"); }
1.int make_server_socket(int port) 用於創建服務端的socket的函數,將在后面進行講解。
2.void handleAccept(int socket_fd) 用於處理連接到服務端的客戶端的函數,將在后面進行講解。
3.thread C++11中出現的用於多線程編程,需要#include <thread> ,以前涉及到多線程編程時,在windows中需要使用CreateThread,而在linux中需要用pthread_create函數
而當thread出現后,在代碼層面上,windows和linux就統一了。
thread的構造函數,
template<class _Fn,class... _Args>
explicit thread(_Fn&& _Fx, _Args&&... _Ax)
{
//
}
簡單來說第一個參數表示函數的名字,其余的參數表示第一個參數所對應函數的參數,模板中的…用到了C++11中的變長模板這一個概念。
比如 t=thread(handleAccept,socket_fd)// handleAccept 函數名字,該函數有一個int的參數,socket_fd對應該int 參數
在線程創建完成后,我用t.detach(),將線程與主線程分離開,這樣線程在線程結束時,就會清空自動該線程所占用的棧空間。並且主線程也可以和支線程一起運行,不用等待支線程結束后才能繼續執行。
而如果我們如果使用t.join();會導致主線程必須等待所有當前的支線程結束后才可以往下執行。這樣就無法同時處理不同客戶端的請求了
還有要注意的是thread默認的joinable值是true,這意味着線程是不會析構的,在重復對同一對象創建線程時是會異常終止的,我們需要使用detach()和join(),將joinable的值改為false
例如
void print() { string a("hello"); cout << a << endl; } int main(int ac, char *av[]) { thread t; t = thread(print);
//t.detach(); t = thread(print); //t.detach(); system("pause"); }
而如果我們把注釋去掉就可以正常運行了,同樣將t.detach()改為t.join()也可以。
關於thread的更多資料
http://www.oschina.net/translate/cplusplus-11-threading-make-your-multitasking-life
http://www.cnblogs.com/haippy/p/3236136.html
4.accept();
accept()函數在windows下
SOCKET accept(SOCKET s,sockaddr* addr,int* addrlen );
accept函數的第一個參數為服務器的socket描述字,第二個參數為指向struct sockaddr *的指針,用於返回客戶端的協議地址,第三個參數為該協議地址的長度。如果accpet成功,那么返回一個socket,代表與返回客戶的TCP連接。
在本程序中
int socket_fd = accept(tcp_socket, nullptr, nullptr);
tcp_socket是我們創建的服務器的socket描述字,而協議地址和該協議地址的長度,我們這里不需要,就設置為nullptr(nullptr為C++11 新增的用於替代null)
在這里accept函數是阻塞的,在沒有新連接請求來的情況下,accept一直在這里等,函數沒有返回,程序也不會往下運行。。
大家可以發現accept在windows中返回的SOCKET類型,而我們用一個int型接受返回值。
大家可以在vs2013中發現
所以SOCKET和int是可以進行轉換的。