什麼是套接字
套接字是一個主機本地應用程序所創建的,爲操作系統所控制的接口。
應用進程通過這個接口,使用傳輸層提供的服務,跨網絡發送/接收消息到其他應用進程。
Client/Server模式的通信接口——套接字接口
套接字:描述符
OS將文件描述符實現爲一個指針數組,指向一個內部的數據結構:進程描述符表的下標
套接字和文件類似,每個活動套接字使用一個小整數標識,進程的文件描述符和套接字描述符值不能相同
socket函數:創建套接字描述符(不是open函數)
進程的文件描述符表
socket
int socket(int domain,int type,int protocol)
功能:創建一個新的套接字,返回套接字描述符
參數說明:
domain:域類型,指明使用的協議棧,如TCP/IP使用的是PF_INET
type:指明需要的服務類型,如
SOCK_DGRAM:數據報服務,UDP協議
SOCK_STREAM:流服務,TCP協議
protocol:一般都取0
舉例:s = socket(PF_INET,SOCK_STREAM,0)
connect
int connect(int sockfd,struct sockaddr *server_addr,int sockaddr_len)
功能:同遠程服務器建立主動連接,成功時返回0,若連接失敗返回-1
參數說明:
Sockfd:套接字描述符,指明創建連接的套接字
Server_addr:指明遠程端點:IP地址和端口號
sockaddr_len:地址長度
舉例(P49):connect(s,remaddr,remaddrlen)
send
int send(int sockfd,const void * data,int data_len,unsigned int flags)
功能:
在TCP連接上發送數據,返回成功傳送數據的長度,出錯時返回-1
send會將外發數據複製到OS內核中,也可以使用send發送面向連接的UDP報文
參數說明:
sockfd:套接字描述符
data:指向要發送數據的指針
data_len:數據長度
flags:一直爲0
recv
int recv(int sockfd,void *buf,int buf_len,unsigned int flags);
功能:
從TCP接收數據,返回實際接收的數據長度,出錯時返回-1
服務器使用其接收客戶請求,客戶使用它接受服務器的應答。如果沒有數據,將阻塞,如果收到的數據大於緩存的大小,多餘的數據將丟棄。也可以使用recv接收面向連接的UDP的報文
參數說明:
Sockfd:套接字描述符
Buf:指向內存塊的指針
Buf_len:內存塊大小,以字節爲單位
flags:一般爲0
舉例:recv(sockfd,buf,8192,0)
close
close(int sockfd);
功能:
撤銷套接字
如果只有一個進程使用,立即終止連接並撤銷套接字,如果多個進程共享該套接字,將引用數減一,如果引用數降到零,則撤銷它。
參數說明:
Sockfd:套接字描述符
舉例:close(socket_descriptor)
bin
int bin(int sockfd,struct sockaddr *my_addr,int addrlen)
功能:爲套接字指明一個本地端點地址
TCP/IP協議使用sockaddr_in結構,包含IP地址和端口號
服務器使用它來指明熟知的端口號,然後等待連接
參數說明:
Sockfd:套接字描述符,指明創建連接的套接字
my_addr:本地地址,IP地址和端口號
addrlen:地址長度
舉例:bin(sockfd,(struct sockaddr*)&address,sizeof(address));
listen
int listen(int sockfd,int input_queue_size)
功能:
面向連接的服務器使用它將一個套接字置爲被動模式,並準備接收傳入連接。用於服務器,指明某個套接字連接是被動的。
參數說明:
Sockfd:套接字描述符,指明創建連接的套接字
input_queue_size:該套接字使用的隊列長度,指定在請求隊列中允許的最大請求數
舉例:listen(sockfd,20)
accept
int accept(int sockfd,void *addr,int *addrlen);
int accept(int sockfd,struct sockaddr *addr,int *addrlen);
功能:獲取傳入連接請求,返回新的連接的套接字描述符。
爲每個新的連接請求創建了一個新的套接字,服務器只對新的連接使用該套接字,原來的監聽套接字接受其他的連接請求。
新的連接上傳輸數據使用新的套接字,使用完畢,服務器將關閉這個套接字。
參數說明:
Sockfd:套接字描述符,指明正在監聽的套接字
addr:提出連接請求的主機地址
addrlen:地址長度
舉例:
new_sockfd = accept(sockfd,(struct sockaddr*)&address,sizeof(address));
用於整數轉換的實用例程
網絡字節順序:最高位字節在前
有結套接字例程要求參數按照網絡字節順序存儲。如sockaddr_in
需要網絡字節順序和本地主機字節順序進行轉換的函數,堅持使用,便於移植。
分爲短(short 16位)和長(long 32位)兩種
htons:將一個短整數從本地字節順序轉換爲網絡字節順序;
ntohs:將一個短整數從網絡字節順序轉換爲本地字節順序;
htonl和ntohl:類似如上
套接字API中的主要系統調用
read和write
在UNIX和Linux中,可以代替recv和send,因爲都調用內核的sosend實現。
Linux
TCP服務端
Ubuntu 16.04.6 LTS
mkdir tcpserver
cd tcpserver
vim tcpserver.cpp
#include <iostream>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
using namespace std;
//#ifndef errno
//extern int errno;
//#endif
int main(int argc,char *argv[])
{
unsigned short port = 8080;
if(argc>1)
{
port = atoi(argv[1]);
}
//1 create socket
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock<=0)
{
cerr<<"cretor socket error "<<strerror(errno)<<endl;
return -1;
}
//2 bind port
sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = htonl(0);
int re = ::bind(sock,(sockaddr*)&saddr,sizeof(saddr));
if(re != 0)
{
cerr<<"bind port "<<port<<" failed!"<<strerror(errno)<<endl;
return -1;
}
cout<<"bind port "<<port<<" success!"<<endl;
//3 listen
listen(sock,10);
//4 accept
{
sockaddr_in caddr;
socklen_t addrlen = 0;
int client_sock = accept(sock,(sockaddr*)&caddr,&addrlen);
cout<<"client sock = "<<client_sock<<endl;
// send
char buf[1024] = "wellcome to xms";
int len = send(client_sock,buf,strlen(buf),0);
cout<<"send len = "<<len<<endl;
// recv
len = recv(client_sock,buf,sizeof(buf)-1,0);
if(len>0)
{
buf[len] = '\0';
cout<<buf<<endl;
}
}
return 0;
}
Ubuntu 18.x
#include <iostream>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
using namespace std;
int main(int argc,char *argv[])
{
unsigned short port = 8080;
if(argc>1)
{
port = atoi(argv[1]);
}
//1 create socket
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock<=0)
{
cerr<<"cretor socket error "<<strerror(errno)<<endl;
return -1;
}
//2 bind port
sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = htonl(0);
int re = ::bind(sock,(sockaddr*)&saddr,sizeof(saddr));
if(re != 0)
{
cerr<<"bind port "<<port<<" failed!"<<strerror(errno)<<endl;
return -1;
}
cout<<"bind port "<<port<<" success!"<<endl;
//3 listen
listen(sock,10);
//4 accept
{
sockaddr_in caddr;
socklen_t addrlen = 0;
int client_sock = accept(sock,(sockaddr*)&caddr,&addrlen);
cout<<"client sock = "<<client_sock<<endl;
// send
char buf[1024] = "wellcome to xms";
int len = send(client_sock,buf,strlen(buf),0);
cout<<"send len = "<<len<<endl;
// recv
len = recv(client_sock,buf,sizeof(buf)-1,0);
if(len>0)
{
buf[len] = '\0';
cout<<buf<<endl;
}
}
return 0;
}
vim makefile
TARGET=tcpserver
OBJS=tcpserver.o
$(TARGET):$(OBJS)
g++ $+ -o $@
clean:
rm -rf $(TARGET)
rm -rf $(OBJS)
make
TCP客戶端
mkdirr tcpclient
touch tcpclient.cpp
cp tcpserver/makefile tcpclient
cd tcpclient
vim tcpclient.cpp
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
using namespace std;
int main(int argc,char *argv[])
{
unsigned short port = 8080;
const char *ip = "127.0.0.1";
//tcpclient 192.168.0.205 8080
if(argc>2)
{
ip = argv[1];
port = atoi(argv[2]);
}
int sock = socket(AF_INET,SOCK_STREAM,0);
sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = inet_addr(ip);
int re = connect(sock,(sockaddr*)&saddr,sizeof(saddr));
if(re != 0)
{
cerr<<"connect "<<ip<<":"<<port<<" failed!"<<strerror(errno)<<endl;
return -1;
}
cout<<"connect "<<ip<<":"<<port<<" success!"<<endl;
char buf[1024] = {0};
int len = recv(sock,buf,sizeof(buf)-1,0);
if(len>0)
{
cout<<buf<<endl;
}
strcpy(buf,"send from client");
len = send(sock,buf,strlen(buf),0);
close(sock);
return 0;
}
makefile
TARGET=tcpclient
OBJS=tcpclient.o
$(TARGET):$(OBJS)
g++ $+ -o $@ -std=c++11
clean:
rm -rf $(TARGET)
rm -rf $(OBJS)
Windows
TCP客戶端
#include <iostream>
#include <sys/types.h>
#ifdef _WIN32
#include <windows.h>
#define close closesocket
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include <string.h>
using namespace std;
int main(int argc,char *argv[])
{
//windows初始化socket庫
#ifdef _WIN32
WSADATA ws;
WSAStartup(MAKEWORD(2, 2), &ws);
#endif
unsigned short port = 8080;
const char *ip = "127.0.0.1";
//tcpclient 192.168.0.205 8080
if(argc>2)
{
ip = argv[1];
port = atoi(argv[2]);
}
int sock = socket(AF_INET,SOCK_STREAM,0);
if (sock < 0)
{
cerr << "socket failed!" << strerror(errno) << endl;
return -1;
}
sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = inet_addr(ip);
int re = connect(sock,(sockaddr*)&saddr,sizeof(saddr));
if(re != 0)
{
cerr<<"connect "<<ip<<":"<<port<<" failed!"<<strerror(errno)<<endl;
return -1;
}
cout<<"connect "<<ip<<":"<<port<<" success!"<<endl;
char buf[1024] = {0};
int len = recv(sock,buf,sizeof(buf)-1,0);
if(len>0)
{
cout<<buf<<endl;
}
strcpy(buf,"send from client");
len = send(sock,buf,strlen(buf),0);
close(sock);
return 0;
}
添加_CRT_SECURE_NO_WARNINGS
添加ws2_32.lib
輸入參數IP+端口
linux server
./tcpserver &
windows client
./tcpclient
libevent和IO模型的學習總結
同步異步和阻塞
socket,阻塞,blocking,結果返回前,當前線程被掛起
epool select,非阻塞,nonblocking,結果返回之前,線程不阻塞
Sync,同步,功能調用無結果不返回,事件一件件做
Async,異步,功能調用後無結果立刻返回,等待通知,一件事沒完成就可以做下一件——IOCP
IO模型
BIO,阻塞IO,Blocking IO,傳統的socket編程方式
NIO,同步非阻塞IO,NonBlocking IO,主動詢問是否就緒,select循環遍歷檢測
AIO,異步非阻塞IO,採用proactor模式,數據完成後,由OS主動通知應用程序IOCP
Reactor模式
event-driven architecture——事件驅動體系結構
reactor設計模式是event-driven architecture的一種實現方式
epoll基於事件驅動思想,採用reactor模式
事件分發器——事件分發器的兩種模式,1Reactor,2Proactor
處理者(event handler)
說明
反應器設計模式(Reactor pattern)是一種爲處理併發服務請求,並將請求提交到一個或者多個服務處理程序的事件設計模式。
當客戶端請求抵達後,服務處理程序使用多路分配策略,由一個非阻塞的線程來接收所有的請求,然後派發這些請求至相關的工作線程進行處理。
簡單說就是如何處理多個客戶端的併發請求的解決模式。
首先Reactor模式中可定義三種角色:
1、Reactor負責監聽和分配事件,將I/O事件分派給對應的Handler
2、Acceptor處理客戶端新連接,並分派請求到處理器鏈中
3、Handlers執行非阻塞讀/寫任務,可用資源池來管理
4、Epoll本質來講是同步非阻塞
Proactor模式
IOCP本質上來講則是異步操作
Windows平臺編譯libevent
-
環境準備
Windows 10 64位
VS2019企業版
perl 編譯openssl用
nasm
zlib 1.2.11源碼,http://zlib.net/
openssl 1.1.1源碼,https://www.openssl.org/source/
libevent 2.1.8源碼, -
編譯zlib
解壓zlib-1.2.11.tar.gz到當前目錄
打開x64_x86 Cross Tools Command Prompt for VS 2019
手動編譯執行
nmake /f WIN32\Makefile.msc
批處理腳本編譯,build_zlib_vs2019_32.bat
set VS="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsamd64_x86.bat"
set OUT = "D:\libevent\out\vs2019_32\zlib"
call %VS%
cd zlib-1.2.11
nmake /f win32\Makefile.msc clean
nmake /f win32\Makefile.msc
md %OUT%\lib
md %OUT%\bin
md %OUT%\include
copy /Y *.lib %OUT%\lib
copy /Y *.h %OUT%\include
copy /Y *.dll %OUT%\bin
copy /Y *.exe %OUT%\bin
pause
上面的bat腳本代碼在不同版本下有可能會報錯,因爲權限的問題,換成下面絕對路徑的寫法
set VS = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsamd64_x86.bat"
set OUT = "D:\libevent\out\vs2019_32\zlib"
call %VS%
cd zlib-1.2.11
nmake /f win32\Makefile.msc clean
nmake /f win32\Makefile.msc
md D:\libevent\out\vs2019_32\zlib\lib
md D:\libevent\out\vs2019_32\zlib\bin
md D:\libevent\out\vs2019_32\zlib\include
copy /Y *.lib D:\libevent\out\vs2019_32\zlib\lib
copy /Y *.h D:\libevent\out\vs2019_32\zlib\include
copy /Y *.dll D:\libevent\out\vs2019_32\zlib\bin
copy /Y *.exe D:\libevent\out\vs2019_32\zlib\bin
pause
以管理員身份運行
- 編譯openssl
安裝 nasm 彙編器,設置PATH環境變量,添加D:\libevent\nasm-2.13.03-win64\nasm-2.13.03
安裝perl,默認安裝即可
手動編譯openssl
打開x64_x86 Cross Tools Command Prompt for VS 2019
set OUTPATH = "D:\libevent\out\vs2019_32\openssl"
perl Configure {VC-WIN32|VC-WIN64|VC-CE} --prefix=%OUTPATH%
批處理腳本編譯
@echo "start compile openssl"
set VS = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsamd64_x86.bat"
set OUT = "D:\libevent\out\vs2019_32\openssl"
call %VS%
D:
cd D:\libevent\openssl-1.1.1g
perl Configure VC-WIN32 --prefix=D:\libevent\out\vs2019_32\openssl
nmake clean
nmake
nmake install
@echo "compile end"
pause
perl Configure VC-WIN32 --prefix=%OUT%
修改成這樣無法正確執行,可能是權限問題,所以建議還是加上絕對路徑。
- 編譯libevent
手動編譯
nmake /f Makefile.nmake OPENSSL_DIR=D:\libevent\out\vs2019_32\openssl
編譯到最後會提示錯誤
LINK : fatal error LNK1181: 無法打開輸入文件 openssl\lib\libeay32.lib
cd D:\libevent\libevent-master\test
修改Makefile.nmake
將SSL_LIBS的libeay32.lib和ssleay32.lib這兩個文件替換成D:\libevent\out\vs2019_32\openssl\lib目錄下的libcrypto.lib和libssl.lib
SSL_LIBS=..\libevent_openssl.lib $(OPENSSL_DIR)\lib\libeay32.lib $(OPENSSL_DIR)\lib\ssleay32.lib gdi32.lib User32.lib
修改爲
SSL_LIBS=..\libevent_openssl.lib $(OPENSSL_DIR)\lib\libcrypto.lib $(OPENSSL_DIR)\lib\libssl.lib gdi32.lib User32.lib
保存再重新手動執行
nmake /f Makefile.nmake OPENSSL_DIR=D:\libevent\out\vs2019_32\openssl clean
nmake /f Makefile.nmake OPENSSL_DIR=D:\libevent\out\vs2019_32\openssl
直到出現這樣的畫面就可以了。
然後檢測一下是否安裝成功,打開目錄D:\libevent\libevent-master\test
運行regress.exe,若仍然提示libcrypto-1_1.dll和libssl-1_1.dll缺失,可以將D:\libevent\out\vs2019_32\openssl\bin目錄下的libcrypto-1_1.dll和libssl-1_1.dll拷貝到D:\libevent\libevent-master\test目錄下,再重新執行regress.exe > …/…/out.txt
發現zlib沒有測試通過,如何解決?
把之前編譯好的zlib整個目錄拷貝到D:\libevent\libevent-master目錄下,並修改Makefile.nmake的CFLAGS,添加/I…/zlib/include
添加regress_zlib.obj
修改D:\libevent\libevent-master\WIN32-Code\nmake\event2\event-config.h
先清除
nmake /f Makefile.nmake OPENSSL_DIR=D:\libevent\out\vs2019_32\openssl clean
再重新編譯
cd D:\libevent\libevent-master
nmake /f Makefile.nmake
最後編譯通過
測試一下zlib例子
cd D:\libevent\libevent-master\test
regress.exe
把zlib1.dll文件拷貝到D:\libevent\libevent-master\test目錄下
D:\libevent\libevent-master\test>regress.exe > ../../out.txt
bufferevent_zlib測試成功了
build_libevent_vs2019_32.bat
@echo "start compile libevent"
set VS = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsamd64_x86.bat"
set OUT = D:\libevent\out\vs2019_32\libevent
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsamd64_x86.bat"
cd /d D:\libevent\libevent-master
nmake /f Makefile.nmake clean
nmake /f Makefile.nmake OPENSSL_DIR=D:\libevent\out\vs2019_32\openssl
md ..\out\vs2019_32\libevent\lib
md ..\out\vs2019_32\libevent\bin
md ..\out\vs2019_32\libevent\include
copy /Y *.lib ..\out\vs2019_32\libevent\lib
xcopy /S/Y include ..\out\vs2019_32\libevent\include
xcopy /S/Y WIN32-Code\nmake ..\out\vs2019_32\libevent\include
copy /Y *.dll ..\out\vs2019_32\libevent\bin
copy /Y *.exe ..\out\vs2019_32\libevent\bin
@echo "compile end"
pause
- 編寫第一個libevent測試程序
visual studio 2019創建控制檯C++應用程序,勾選“解決方案和項目放在同一目錄”,工程項目保存到src目錄下
工程目錄結構如下:
項目工程右鍵屬性,分別修改以下參數
(1)c/c++===> 預編譯頭 =>不使用預編譯頭
(2)c/c++=> 常規 ===> 附加包含目錄,添加…\include
(3)鏈接器 ===> 常規 ===> 附加庫目錄,添加…\lib
(4)鏈接器 ===> 輸入 ===> 附加依賴項,添加libevent.lib;ws2_32.lib
(5)鏈接器 ===> 命令行 ,添加/NODEFAULTLIB:“libcmtd.lib”
修改main.cpp
#include <iostream>
#include <event2/event.h>
using namespace std;
int main()
{
#ifdef _WIN32
//初始化socket庫,windows平臺下一定要初始化socket庫,而linux平臺不用
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
#endif
std::cout << "test libevent!\n";
event_base* base = event_base_new();
if (base)
{
cout << "event_base_new success!" << endl;
}
system("pause");
return 0;
}
執行成功
test libevent!
event_base_new success!
Linux平臺編譯libevent
ubuntu18.04.01 64
apt-get install perl g++ make automake libtool unzip
zlib
tar -xvf zlib-1.2.11.tar.gz
cd zlib-1.2.11
./configure
make -j6
sudo make install
可以看到庫文件都拷貝到/usr/local/lib目錄下,頭文件在/usr/local/include目錄,在這些目錄的文件,你的程序可以不用指定庫文件路徑,頭文件也是一樣。
openssl-1.1.1
tar -xvf openssl-1.1.1.tar.gz
./config
make -j6
sudo make install
同樣在安裝的時候也是把這些生成的文件拷貝到這些目錄下
/usr/local/lib/
/usr/local/include
……
你的程序可以不用指定庫文件路徑,頭文件也是一樣。
libevent
在安裝libevent之前,確保你的linux系統已經安裝automake和libtool
unzip libevent-master.zip
cd libevent-master
./autogen.sh 生成configure
./configure
make -j6
sudo make install
test/regress >log.txt
zlib測試通過
ssl測試通過
在原來first-libevent項目的基礎上修改一下,直接在linux環境下編譯。
vim makefile
firstlibevent:first_libevent.cpp
g++ $^ -o $@ -levent
./$@
clean:
rm -rf firstlibevent
rm -rf *.o
按下esc,wq退出
$: make
g++ first_libevent.cpp -o firstlibevent -levent -L /usr/local/lib
./firstlibevent
./firstlibevent: error while loading shared libraries: libevent-2.2.so.1: cannot open shared object file: No such file or directory
linux 缺少動態連接庫.so——cannot open shared object file: No such file or directory
$: whereis libevent-2.2.so
.1
libevent-2.2.so: /usr/local/lib/libevent-2.2.so.1
$: ldd /usr/local/lib/libevent-2.2.so.1
linux-vdso.so.1 => (0x00007fff8638f000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3e29e84000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3e29aba000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3e2a2f8000)
libevent-2.2.so.1軟鏈接的路徑是正常存在的,出現這種情況,有可能是$LD_LIBRARY_PATH環境變量設置的問題
(caffe2_env) zhoujianwen@zhoujianwen-System:/media/zhoujianwen/Data/libevent/src/first_libevent$ echo $LD_LIBRARY_PATH
/usr/local/cuda-10.0/lib64
在makefile頭部添加
LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
注意:它只對當次make執行操作有效,make之後再單獨執行./firstlibevent仍然會提示找不到共享庫xxx.so,要永久性添加就要將該 LD_LIBRARY_PATH 的 export 語句寫到系統文件中,結尾會提及到。
vim makefile
LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
firstlibevent:first_libevent.cpp
g++ $^ -o $@ -levent
./$@
clean:
rm -rf firstlibevent
rm -rf *.o
(caffe2_env) zhoujianwen@zhoujianwen-System:/media/zhoujianwen/Data/libevent/src/first_libevent$ make clean
rm -rf firstlibevent
rm -rf *.o
(caffe2_env) zhoujianwen@zhoujianwen-System:/media/zhoujianwen/Data/libevent/src/first_libevent$ make
g++ first_libevent.cpp -o firstlibevent -levent
./firstlibevent
test libevent!
event_base_new success!
linux中每次裝完一個新的庫,需要進行ldconfig命令
sudo ldconfig
https://www.pianshen.com/article/8867176161/
https://blog.csdn.net/qq_33343767/article/details/90378535
爲什麼修改LD_LIBRARY_PATH呢
因爲運行時動態庫的搜索路徑的先後順序是:
1.編譯目標代碼時指定的動態庫搜索路徑;
2.環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑;
3.配置文件/etc/ld.so.conf中指定的動態庫搜索路徑;
4.默認的動態庫搜索路徑/lib和/usr/lib;
這個順序是compile gcc時寫在程序內的,通常軟件源代碼自帶的動態庫不會太多,而我們的/lib和/usr/lib只有root權限纔可以修改,而且配置文件/etc/ld.so.conf也是root的事情,我們只好對LD_LIBRARY_PATH進行操作啦。
永久性添加
每次我使用該軟件都需要臨時修改庫文件,因爲上面的方法是臨時設置環境變量 LD_LIBRARY_PATH ,重啓或打開新的 Shell 之後,一切設置將不復存在。
爲了讓這種方法更完美一些,可以將該 LD_LIBRARY_PATH 的 export 語句寫到系統文件中,例如 /etc/profile、/etc/export、~/.bashrc 或者 ~/.bash_profile 等等,取決於你正在使用的操作系統咯。
修改完系統文件記得source ~/.bashrc
纔會生效。
基於event監控客戶端接收連接
event註冊服務端接收連接事件
(1) 創建event_base上下文
(2) 創建socket綁定端口
(3) 註冊socket監聽事件的回調函數
(4) 接收客戶端連接
搭建服務器接收用戶連接——evconnlistener_new_bind
使用bufferevent連接服務器
基於bufferevent數據通信
服務器端幾種模型:
1、阻塞式模型(blocking IO)
2、多線程的服務器模型(Multi-Thread)
3、非阻塞式模型(Non-blocking IO)
4、多路複用IO
5、使用事件驅動庫libevent的服務器模型
6、信號驅動IO模型(Signal-driven IO)
7、異步IO模型(asynchronous IO)
幾種服務器端IO模型的簡單介紹及實現 http://www.cnblogs.com/luxiaoxun/p/3691800.html