├── Makefile
├── README.md
├── VS2017
├── rtsp.sln
├── rtsp.vcxproj
├── rtsp.vcxproj.filters
├── rtsp.vcxproj.user
└── x64
│ ├── Debug
│ ├── rtsp.Build.CppClean.log
│ ├── rtsp.log
│ └── rtsp.vcxproj.FileListAbsolute.txt
│ └── Release
│ ├── rtsp.Build.CppClean.log
│ ├── rtsp.log
│ └── rtsp.vcxproj.FileListAbsolute.txt
├── example
├── rtsp_h264_file.cpp
├── rtsp_h265.cpp
├── rtsp_pusher.cpp
└── rtsp_server.cpp
├── pic
└── 1.pic.JPG
├── src
├── 3rdpart
│ └── md5
│ │ ├── COPYING
│ │ └── md5.hpp
├── net
│ ├── Acceptor.cpp
│ ├── Acceptor.h
│ ├── BufferReader.cpp
│ ├── BufferReader.h
│ ├── BufferWriter.cpp
│ ├── BufferWriter.h
│ ├── Channel.h
│ ├── EpollTaskScheduler.cpp
│ ├── EpollTaskScheduler.h
│ ├── EventLoop.cpp
│ ├── EventLoop.h
│ ├── Logger.cpp
│ ├── Logger.h
│ ├── MemoryManager.cpp
│ ├── MemoryManager.h
│ ├── NetInterface.cpp
│ ├── NetInterface.h
│ ├── Pipe.cpp
│ ├── Pipe.h
│ ├── RingBuffer.h
│ ├── SelectTaskScheduler.cpp
│ ├── SelectTaskScheduler.h
│ ├── Socket.h
│ ├── SocketUtil.cpp
│ ├── SocketUtil.h
│ ├── TaskScheduler.cpp
│ ├── TaskScheduler.h
│ ├── TcpConnection.cpp
│ ├── TcpConnection.h
│ ├── TcpServer.cpp
│ ├── TcpServer.h
│ ├── TcpSocket.cpp
│ ├── TcpSocket.h
│ ├── ThreadSafeQueue.h
│ ├── Timer.cpp
│ ├── Timer.h
│ ├── Timestamp.cpp
│ ├── Timestamp.h
│ └── log.h
└── xop
│ ├── AACSource.cpp
│ ├── AACSource.h
│ ├── DigestAuthentication.cpp
│ ├── DigestAuthentication.h
│ ├── G711ASource.cpp
│ ├── G711ASource.h
│ ├── H264Parser.cpp
│ ├── H264Parser.h
│ ├── H264Source.cpp
│ ├── H264Source.h
│ ├── H265Source.cpp
│ ├── H265Source.h
│ ├── MediaSession.cpp
│ ├── MediaSession.h
│ ├── MediaSource.h
│ ├── RtpConnection.cpp
│ ├── RtpConnection.h
│ ├── RtspConnection.cpp
│ ├── RtspConnection.h
│ ├── RtspMessage.cpp
│ ├── RtspMessage.h
│ ├── RtspPusher.cpp
│ ├── RtspPusher.h
│ ├── RtspServer.cpp
│ ├── RtspServer.h
│ ├── media.h
│ ├── rtp.h
│ └── rtsp.h
└── test.h265
/Makefile:
--------------------------------------------------------------------------------
1 | DEUBG = -D_DEBUG
2 |
3 | TARGET1 = rtsp_server
4 | TARGET2 = rtsp_pusher
5 | TARGET3 = rtsp_h264_file
6 |
7 | OBJS_PATH = objs
8 |
9 | CROSS_COMPILE =
10 | CXX = $(CROSS_COMPILE)g++
11 | CC = $(CROSS_COMPILE)gcc
12 | STRIP = $(CROSS_COMPILE)strip
13 |
14 | INC = -I$(shell pwd)/src/ -I$(shell pwd)/src/net -I$(shell pwd)/src/xop -I$(shell pwd)/src/3rdpart
15 | LIB =
16 |
17 | LD_FLAGS = -lrt -pthread -lpthread -ldl -lm $(DEBUG)
18 | CXX_FLAGS = -std=c++11
19 |
20 | O_FLAG = -O2
21 |
22 | SRC1 = $(notdir $(wildcard ./src/net/*.cpp))
23 | OBJS1 = $(patsubst %.cpp,$(OBJS_PATH)/%.o,$(SRC1))
24 |
25 | SRC2 = $(notdir $(wildcard ./src/xop/*.cpp))
26 | OBJS2 = $(patsubst %.cpp,$(OBJS_PATH)/%.o,$(SRC2))
27 |
28 | SRC3 = $(notdir $(wildcard ./example/rtsp_server.cpp))
29 | OBJS3 = $(patsubst %.cpp,$(OBJS_PATH)/%.o,$(SRC3))
30 |
31 | SRC4 = $(notdir $(wildcard ./example/rtsp_pusher.cpp))
32 | OBJS4 = $(patsubst %.cpp,$(OBJS_PATH)/%.o,$(SRC4))
33 |
34 | SRC5 = $(notdir $(wildcard ./example/rtsp_h264_file.cpp))
35 | OBJS5 = $(patsubst %.cpp,$(OBJS_PATH)/%.o,$(SRC5))
36 |
37 | all: BUILD_DIR $(TARGET1) $(TARGET2) $(TARGET3)
38 |
39 | BUILD_DIR:
40 | @-mkdir -p $(OBJS_PATH)
41 |
42 | $(TARGET1) : $(OBJS1) $(OBJS2) $(OBJS3)
43 | $(CXX) $^ -o $@ $(CFLAGS) $(LD_FLAGS) $(CXX_FLAGS)
44 |
45 | $(TARGET2) : $(OBJS1) $(OBJS2) $(OBJS4)
46 | $(CXX) $^ -o $@ $(CFLAGS) $(LD_FLAGS) $(CXX_FLAGS)
47 |
48 | $(TARGET3) : $(OBJS1) $(OBJS2) $(OBJS5)
49 | $(CXX) $^ -o $@ $(CFLAGS) $(LD_FLAGS) $(CXX_FLAGS)
50 |
51 | $(OBJS_PATH)/%.o : ./example/%.cpp
52 | $(CXX) -c $< -o $@ $(CXX_FLAGS) $(INC)
53 | $(OBJS_PATH)/%.o : ./src/net/%.cpp
54 | $(CXX) -c $< -o $@ $(CXX_FLAGS) $(INC)
55 | $(OBJS_PATH)/%.o : ./src/xop/%.cpp
56 | $(CXX) -c $< -o $@ $(CXX_FLAGS) $(INC)
57 |
58 | clean:
59 | -rm -rf $(OBJS_PATH) $(TARGET1) $(TARGET2) $(TARGET3)
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # rtspServerH265
2 | Use rtsp protocol to push local H265 video encoding files
3 | 项目介绍
4 | -
5 | * C++11实现的RTSP服务器和推流器。主要完成对H265视频编码文件的RTSP推流
6 |
7 | 使用说明
8 | -
9 | * 1.编译并运行程序;
10 | * 2.打开VLC软件,在媒体-->打开网络串流输入:rtsp://127.0.0.1:554/codec2021 ,点VLC的播放按钮
11 | * 3.即可在VLC软件看到本地H265码流文件的画面
12 |
13 | 编译环境
14 | -
15 | * Linux: gcc 4.8
16 | * Windows: vs2017以上
17 |
18 | 感谢
19 | -
20 | * https://github.com/PHZ76/RtspServer
21 |
22 |
23 | 联系方式
24 | -
25 | * 21510025@zju.edu.cn
26 |
--------------------------------------------------------------------------------
/VS2017/rtsp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.645
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtsp", "rtsp.vcxproj", "{EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Debug|x64.ActiveCfg = Debug|x64
17 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Debug|x64.Build.0 = Debug|x64
18 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Debug|x86.ActiveCfg = Debug|Win32
19 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Debug|x86.Build.0 = Debug|Win32
20 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Release|x64.ActiveCfg = Release|x64
21 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Release|x64.Build.0 = Release|x64
22 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Release|x86.ActiveCfg = Release|Win32
23 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {6644BEFC-17EF-4D94-9620-AC36DCD57B40}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/VS2017/rtsp.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}
24 | rtsp
25 | 10.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v142
32 | MultiByte
33 |
34 |
35 | Application
36 | false
37 | v142
38 | true
39 | MultiByte
40 |
41 |
42 | Application
43 | true
44 | v142
45 | MultiByte
46 |
47 |
48 | Application
49 | false
50 | v142
51 | true
52 | MultiByte
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Level3
76 | Disabled
77 | true
78 | true
79 | $(ProjectDir)..\src;$(ProjectDir)..\src\3rdpart;%(AdditionalIncludeDirectories)
80 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
81 |
82 |
83 |
84 |
85 | Level3
86 | Disabled
87 | true
88 | true
89 | $(ProjectDir)..\src;$(ProjectDir)..\src\3rdpart;%(AdditionalIncludeDirectories)
90 | _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;%(PreprocessorDefinitions)
91 |
92 |
93 | %(AdditionalDependencies)
94 |
95 |
96 |
97 |
98 |
99 |
100 | Level3
101 | MaxSpeed
102 | true
103 | true
104 | true
105 | true
106 | $(ProjectDir)..\src;$(ProjectDir)..\src\3rdpart;%(AdditionalIncludeDirectories)
107 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
108 |
109 |
110 | true
111 | true
112 |
113 |
114 |
115 |
116 | Level3
117 | MaxSpeed
118 | true
119 | true
120 | true
121 | true
122 | $(ProjectDir)..\src;$(ProjectDir)..\src\3rdpart;%(AdditionalIncludeDirectories)
123 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
124 |
125 |
126 | true
127 | true
128 |
129 |
130 | %(AdditionalDependencies)
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
--------------------------------------------------------------------------------
/VS2017/rtsp.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {93fd1892-c18d-4be0-8936-a01a836e79c7}
18 |
19 |
20 | {f0200b67-2e3e-4d18-92fb-6a9ef1d1d4d3}
21 |
22 |
23 | {dcb79e29-beb4-4205-a5a7-9e8b373ac709}
24 |
25 |
26 | {bd328520-ced7-4f34-a7db-68df5cb07909}
27 |
28 |
29 |
30 |
31 | 源文件\xop
32 |
33 |
34 | 源文件\xop
35 |
36 |
37 | 源文件\xop
38 |
39 |
40 | 源文件\xop
41 |
42 |
43 | 源文件\xop
44 |
45 |
46 | 源文件\xop
47 |
48 |
49 | 源文件\xop
50 |
51 |
52 | 源文件\xop
53 |
54 |
55 | 源文件\xop
56 |
57 |
58 | 源文件\xop
59 |
60 |
61 | 源文件\xop
62 |
63 |
64 | 源文件\net
65 |
66 |
67 | 源文件\net
68 |
69 |
70 | 源文件\net
71 |
72 |
73 | 源文件\net
74 |
75 |
76 | 源文件\net
77 |
78 |
79 | 源文件\net
80 |
81 |
82 | 源文件\net
83 |
84 |
85 | 源文件\net
86 |
87 |
88 | 源文件\net
89 |
90 |
91 | 源文件\net
92 |
93 |
94 | 源文件\net
95 |
96 |
97 | 源文件\net
98 |
99 |
100 | 源文件\net
101 |
102 |
103 | 源文件\net
104 |
105 |
106 | 源文件\net
107 |
108 |
109 | 源文件\net
110 |
111 |
112 | 源文件\net
113 |
114 |
115 | 源文件\xop
116 |
117 |
118 | 源文件
119 |
120 |
121 |
122 |
123 | 源文件\xop
124 |
125 |
126 | 源文件\xop
127 |
128 |
129 | 源文件\xop
130 |
131 |
132 | 源文件\xop
133 |
134 |
135 | 源文件\xop
136 |
137 |
138 | 源文件\xop
139 |
140 |
141 | 源文件\xop
142 |
143 |
144 | 源文件\xop
145 |
146 |
147 | 源文件\xop
148 |
149 |
150 | 源文件\xop
151 |
152 |
153 | 源文件\xop
154 |
155 |
156 | 源文件\xop
157 |
158 |
159 | 源文件\xop
160 |
161 |
162 | 源文件\xop
163 |
164 |
165 | 源文件\xop
166 |
167 |
168 | 源文件\net
169 |
170 |
171 | 源文件\net
172 |
173 |
174 | 源文件\net
175 |
176 |
177 | 源文件\net
178 |
179 |
180 | 源文件\net
181 |
182 |
183 | 源文件\net
184 |
185 |
186 | 源文件\net
187 |
188 |
189 | 源文件\net
190 |
191 |
192 | 源文件\net
193 |
194 |
195 | 源文件\net
196 |
197 |
198 | 源文件\net
199 |
200 |
201 | 源文件\net
202 |
203 |
204 | 源文件\net
205 |
206 |
207 | 源文件\net
208 |
209 |
210 | 源文件\net
211 |
212 |
213 | 源文件\net
214 |
215 |
216 | 源文件\net
217 |
218 |
219 | 源文件\net
220 |
221 |
222 | 源文件\net
223 |
224 |
225 | 源文件\net
226 |
227 |
228 | 源文件\net
229 |
230 |
231 | 源文件\net
232 |
233 |
234 | 源文件\xop
235 |
236 |
237 | 源文件\3rdpart\md5
238 |
239 |
240 |
--------------------------------------------------------------------------------
/VS2017/rtsp.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(ProjectDir)..\
5 | WindowsLocalDebugger
6 | test.h264
7 |
8 |
9 | $(ProjectDir)..\
10 | WindowsLocalDebugger
11 | test.h264
12 |
13 |
14 | $(ProjectDir)..\
15 | WindowsLocalDebugger
16 | test.h265
17 |
18 |
19 | $(ProjectDir)..\
20 | WindowsLocalDebugger
21 | test.h265
22 |
23 |
--------------------------------------------------------------------------------
/VS2017/x64/Debug/rtsp.Build.CppClean.log:
--------------------------------------------------------------------------------
1 | f:\rtspserver-master\vs2017\x64\debug\vc142.pdb
2 | f:\rtspserver-master\vs2017\x64\debug\vc142.idb
3 | f:\rtspserver-master\vs2017\x64\debug\digestauthentication.obj
4 | f:\rtspserver-master\vs2017\x64\debug\aacsource.obj
5 | f:\rtspserver-master\vs2017\x64\debug\timestamp.obj
6 | f:\rtspserver-master\vs2017\x64\debug\timer.obj
7 | f:\rtspserver-master\vs2017\x64\debug\tcpsocket.obj
8 | f:\rtspserver-master\vs2017\x64\debug\tcpserver.obj
9 | f:\rtspserver-master\vs2017\x64\debug\tcpconnection.obj
10 | f:\rtspserver-master\vs2017\x64\debug\taskscheduler.obj
11 | f:\rtspserver-master\vs2017\x64\debug\socketutil.obj
12 | f:\rtspserver-master\vs2017\x64\debug\selecttaskscheduler.obj
13 | f:\rtspserver-master\vs2017\x64\debug\pipe.obj
14 | f:\rtspserver-master\vs2017\x64\debug\netinterface.obj
15 | f:\rtspserver-master\vs2017\x64\debug\memorymanager.obj
16 | f:\rtspserver-master\vs2017\x64\debug\logger.obj
17 | f:\rtspserver-master\vs2017\x64\debug\eventloop.obj
18 | f:\rtspserver-master\vs2017\x64\debug\epolltaskscheduler.obj
19 | f:\rtspserver-master\vs2017\x64\debug\bufferwriter.obj
20 | f:\rtspserver-master\vs2017\x64\debug\bufferreader.obj
21 | f:\rtspserver-master\vs2017\x64\debug\acceptor.obj
22 | f:\rtspserver-master\vs2017\x64\debug\rtsp_h265.obj
23 | f:\rtspserver-master\vs2017\x64\debug\rtspserver.obj
24 | f:\rtspserver-master\vs2017\x64\debug\rtsppusher.obj
25 | f:\rtspserver-master\vs2017\x64\debug\rtspmessage.obj
26 | f:\rtspserver-master\vs2017\x64\debug\rtspconnection.obj
27 | f:\rtspserver-master\vs2017\x64\debug\rtpconnection.obj
28 | f:\rtspserver-master\vs2017\x64\debug\mediasession.obj
29 | f:\rtspserver-master\vs2017\x64\debug\h265source.obj
30 | f:\rtspserver-master\vs2017\x64\debug\h264source.obj
31 | f:\rtspserver-master\vs2017\x64\debug\h264parser.obj
32 | f:\rtspserver-master\vs2017\x64\debug\g711asource.obj
33 | f:\rtspserver-master\vs2017\x64\debug\rtsp.exe
34 | f:\rtspserver-master\vs2017\x64\debug\rtsp.ilk
35 | f:\rtspserver-master\vs2017\x64\debug\rtsp.pdb
36 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\aacsource.obj
37 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\acceptor.obj
38 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\bufferreader.obj
39 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\bufferwriter.obj
40 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\digestauthentication.obj
41 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\epolltaskscheduler.obj
42 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\eventloop.obj
43 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\g711asource.obj
44 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\h264parser.obj
45 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\h264source.obj
46 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\h265source.obj
47 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\logger.obj
48 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\mediasession.obj
49 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\memorymanager.obj
50 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\netinterface.obj
51 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\pipe.obj
52 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtpconnection.obj
53 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtspconnection.obj
54 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtspmessage.obj
55 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsppusher.obj
56 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtspserver.obj
57 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp_h265.obj
58 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\selecttaskscheduler.obj
59 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\socketutil.obj
60 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\taskscheduler.obj
61 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\tcpconnection.obj
62 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\tcpserver.obj
63 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\tcpsocket.obj
64 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\timer.obj
65 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\timestamp.obj
66 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.ilk
67 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\vc142.idb
68 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.pdb
69 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\vc142.pdb
70 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.exe
71 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\cl.command.1.tlog
72 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\cl.read.1.tlog
73 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\cl.write.1.tlog
74 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\link.command.1.tlog
75 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\link.read.1.tlog
76 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\link.write.1.tlog
77 |
--------------------------------------------------------------------------------
/VS2017/x64/Debug/rtsp.log:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/VS2017/x64/Debug/rtsp.vcxproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | C:\Users\84038\Desktop\RtspServer-master\VS2017\x64\Debug\rtsp.exe
2 | C:\Users\84038\Desktop\RtspServer-master\VS2017\x64\Debug\rtsp.pdb
3 | D:\fxx\桌面\FAN\7月\RtspServer-master\VS2017\x64\Debug\rtsp.exe
4 | D:\fxx\桌面\FAN\7月\RtspServer-master\VS2017\x64\Debug\rtsp.pdb
5 | F:\RtspServer-master\VS2017\x64\Debug\rtsp.exe
6 | F:\RtspServer-master\VS2017\x64\Debug\rtsp.pdb
7 |
--------------------------------------------------------------------------------
/VS2017/x64/Release/rtsp.Build.CppClean.log:
--------------------------------------------------------------------------------
1 | f:\rtspserver-master\vs2017\x64\release\vc142.pdb
2 | f:\rtspserver-master\vs2017\x64\release\x265_encode.obj
3 | f:\rtspserver-master\vs2017\x64\release\rtsp_h265.obj
4 | f:\rtspserver-master\vs2017\x64\release\digestauthentication.obj
5 | f:\rtspserver-master\vs2017\x64\release\aacsource.obj
6 | f:\rtspserver-master\vs2017\x64\release\timestamp.obj
7 | f:\rtspserver-master\vs2017\x64\release\timer.obj
8 | f:\rtspserver-master\vs2017\x64\release\tcpsocket.obj
9 | f:\rtspserver-master\vs2017\x64\release\tcpserver.obj
10 | f:\rtspserver-master\vs2017\x64\release\tcpconnection.obj
11 | f:\rtspserver-master\vs2017\x64\release\taskscheduler.obj
12 | f:\rtspserver-master\vs2017\x64\release\socketutil.obj
13 | f:\rtspserver-master\vs2017\x64\release\selecttaskscheduler.obj
14 | f:\rtspserver-master\vs2017\x64\release\pipe.obj
15 | f:\rtspserver-master\vs2017\x64\release\netinterface.obj
16 | f:\rtspserver-master\vs2017\x64\release\memorymanager.obj
17 | f:\rtspserver-master\vs2017\x64\release\logger.obj
18 | f:\rtspserver-master\vs2017\x64\release\eventloop.obj
19 | f:\rtspserver-master\vs2017\x64\release\epolltaskscheduler.obj
20 | f:\rtspserver-master\vs2017\x64\release\bufferwriter.obj
21 | f:\rtspserver-master\vs2017\x64\release\bufferreader.obj
22 | f:\rtspserver-master\vs2017\x64\release\acceptor.obj
23 | f:\rtspserver-master\vs2017\x64\release\rtspserver.obj
24 | f:\rtspserver-master\vs2017\x64\release\rtsppusher.obj
25 | f:\rtspserver-master\vs2017\x64\release\rtspmessage.obj
26 | f:\rtspserver-master\vs2017\x64\release\rtspconnection.obj
27 | f:\rtspserver-master\vs2017\x64\release\rtpconnection.obj
28 | f:\rtspserver-master\vs2017\x64\release\mediasession.obj
29 | f:\rtspserver-master\vs2017\x64\release\h265source.obj
30 | f:\rtspserver-master\vs2017\x64\release\h264source.obj
31 | f:\rtspserver-master\vs2017\x64\release\h264parser.obj
32 | f:\rtspserver-master\vs2017\x64\release\g711asource.obj
33 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\vc142.pdb
34 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\digestauthentication.obj
35 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\aacsource.obj
36 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\timestamp.obj
37 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\timer.obj
38 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\tcpsocket.obj
39 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\tcpserver.obj
40 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\tcpconnection.obj
41 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\taskscheduler.obj
42 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\socketutil.obj
43 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\selecttaskscheduler.obj
44 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\pipe.obj
45 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\netinterface.obj
46 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\memorymanager.obj
47 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\logger.obj
48 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\eventloop.obj
49 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\epolltaskscheduler.obj
50 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\bufferwriter.obj
51 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\bufferreader.obj
52 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\acceptor.obj
53 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp_h265.obj
54 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtspserver.obj
55 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsppusher.obj
56 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtspmessage.obj
57 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtspconnection.obj
58 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtpconnection.obj
59 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\mediasession.obj
60 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\h265source.obj
61 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\h264source.obj
62 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\h264parser.obj
63 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\g711asource.obj
64 | f:\rtspserver-master\vs2017\x64\release\rtsp.exe
65 | f:\rtspserver-master\vs2017\x64\release\rtsp.pdb
66 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.exe
67 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.pdb
68 | f:\rtspserver-master\vs2017\x64\release\rtsp.ipdb
69 | f:\rtspserver-master\vs2017\x64\release\rtsp.iobj
70 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.ipdb
71 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.iobj
72 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\x265_encode.obj
73 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\cl.command.1.tlog
74 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\cl.read.1.tlog
75 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\cl.write.1.tlog
76 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\link.command.1.tlog
77 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\link.read.1.tlog
78 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\link.write.1.tlog
79 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\rtsp.write.1u.tlog
80 |
--------------------------------------------------------------------------------
/VS2017/x64/Release/rtsp.log:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/VS2017/x64/Release/rtsp.vcxproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | F:\RtspServer-master\VS2017\x64\Release\rtsp.exe
2 |
--------------------------------------------------------------------------------
/example/rtsp_h264_file.cpp:
--------------------------------------------------------------------------------
1 | // RTSP Server
2 |
3 | #include "xop/RtspServer.h"
4 | #include "net/Timer.h"
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | class H264File
11 | {
12 | public:
13 | H264File(int buf_size=500000);
14 | ~H264File();
15 |
16 | bool Open(const char *path);
17 | void Close();
18 |
19 | bool IsOpened() const
20 | { return (m_file != NULL); }
21 |
22 | int ReadFrame(char* in_buf, int in_buf_size, bool* end);
23 |
24 | private:
25 | FILE *m_file = NULL;
26 | char *m_buf = NULL;
27 | int m_buf_size = 0;
28 | int m_bytes_used = 0;
29 | int m_count = 0;
30 | };
31 |
32 | void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, H264File* h264_file);
33 |
34 | #if 0
35 | int main(int argc, char **argv)
36 | {
37 | if(argc != 2) {
38 | printf("Usage: %s test.h264\n", argv[0]);
39 | return 0;
40 | }
41 |
42 | H264File h264_file;
43 | if(!h264_file.Open(argv[1])) {
44 | printf("Open %s failed.\n", argv[1]);
45 | return 0;
46 | }
47 |
48 | std::string suffix = "live";
49 | std::string ip = "127.0.0.1";
50 | std::string port = "554";
51 | std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;
52 |
53 | std::shared_ptr event_loop(new xop::EventLoop());
54 | std::shared_ptr server = xop::RtspServer::Create(event_loop.get());
55 |
56 | if (!server->Start("0.0.0.0", atoi(port.c_str()))) {
57 | printf("RTSP Server listen on %s failed.\n", port.c_str());
58 | return 0;
59 | }
60 |
61 | #ifdef AUTH_CONFIG
62 | server->SetAuthConfig("-_-", "admin", "12345");
63 | #endif
64 |
65 | xop::MediaSession *session = xop::MediaSession::CreateNew("live");
66 | session->AddSource(xop::channel_0, xop::H264Source::CreateNew());
67 | //session->StartMulticast();
68 | session->SetNotifyCallback([] (xop::MediaSessionId session_id, uint32_t clients){
69 | std::cout << "The number of rtsp clients: " << clients << std::endl;
70 | });
71 |
72 | xop::MediaSessionId session_id = server->AddSession(session);
73 |
74 | std::thread t1(SendFrameThread, server.get(), session_id, &h264_file);
75 | t1.detach();
76 |
77 | std::cout << "Play URL: " << rtsp_url << std::endl;
78 |
79 | while (1) {
80 | xop::Timer::Sleep(100);
81 | }
82 |
83 | getchar();
84 | return 0;
85 | }
86 | #endif
87 |
88 | void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, H264File* h264_file)
89 | {
90 | int buf_size = 2000000;
91 | std::unique_ptr frame_buf(new uint8_t[buf_size]);
92 |
93 | while(1) {
94 | bool end_of_frame = false;
95 | int frame_size = h264_file->ReadFrame((char*)frame_buf.get(), buf_size, &end_of_frame);
96 | if(frame_size > 0) {
97 | xop::AVFrame videoFrame = {0};
98 | videoFrame.type = 0;
99 | videoFrame.size = frame_size;
100 | videoFrame.timestamp = xop::H264Source::GetTimestamp();
101 | videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
102 | memcpy(videoFrame.buffer.get(), frame_buf.get(), videoFrame.size);
103 | rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame);
104 | }
105 | else {
106 | break;
107 | }
108 |
109 | xop::Timer::Sleep(40);
110 | };
111 | }
112 |
113 | H264File::H264File(int buf_size)
114 | : m_buf_size(buf_size)
115 | {
116 | m_buf = new char[m_buf_size];
117 | }
118 |
119 | H264File::~H264File()
120 | {
121 | delete m_buf;
122 | }
123 |
124 | bool H264File::Open(const char *path)
125 | {
126 | m_file = fopen(path, "rb");
127 | if(m_file == NULL)
128 | {
129 | return false;
130 | }
131 |
132 | return true;
133 | }
134 |
135 | void H264File::Close()
136 | {
137 | if(m_file) {
138 | fclose(m_file);
139 | m_file = NULL;
140 | m_count = 0;
141 | m_bytes_used = 0;
142 | }
143 | }
144 |
145 | int H264File::ReadFrame(char* in_buf, int in_buf_size, bool* end)
146 | {
147 | if(m_file == NULL) {
148 | return -1;
149 | }
150 |
151 | int bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file);
152 | if(bytes_read == 0)
153 | {
154 | fseek(m_file, 0, SEEK_SET);
155 | m_count = 0;
156 | m_bytes_used = 0;
157 | bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file);
158 | if(bytes_read == 0)
159 | {
160 | this->Close();
161 | return -1;
162 | }
163 | }
164 |
165 | bool is_find_start = false, is_find_end = false;
166 | int i = 0, start_code = 3;
167 | *end = false;
168 |
169 | for (i=0; i0) {
211 | flag = is_find_end = true;
212 | i = bytes_read;
213 | *end = true;
214 | }
215 |
216 | if(!is_find_start || !is_find_end) {
217 | this->Close();
218 | return -1;
219 | }
220 |
221 | int size = (i<=in_buf_size ? i : in_buf_size);
222 | memcpy(in_buf, m_buf, size);
223 |
224 | if(!flag) {
225 | m_count += 1;
226 | m_bytes_used += i;
227 | }
228 | else {
229 | m_count = 0;
230 | m_bytes_used = 0;
231 | }
232 |
233 | fseek(m_file, m_bytes_used, SEEK_SET);
234 | return size;
235 | }
236 |
237 |
238 |
--------------------------------------------------------------------------------
/example/rtsp_h265.cpp:
--------------------------------------------------------------------------------
1 | // RTSP Server
2 | #include "xop/RtspServer.h"
3 | #include "net/Timer.h"
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #define MAX_FRAME_SIZE 500000
10 |
11 | class H265File
12 | {
13 | public:
14 | H265File(int buf_size = MAX_FRAME_SIZE);
15 | ~H265File();
16 |
17 | bool Open(const char *path);
18 | void Close();
19 |
20 | bool IsOpened() const
21 | {
22 | return (m_file != NULL);
23 | }
24 |
25 | int ReadFrame(char* in_buf, int in_buf_size, bool* end);
26 |
27 | private:
28 | FILE *m_file = NULL;
29 | char *m_buf = NULL;
30 | int m_buf_size = 0;
31 | int m_bytes_used = 0;
32 | int m_count = 0;
33 | };
34 |
35 |
36 | void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, H265File* h265_file)
37 | {
38 | int buf_size = MAX_FRAME_SIZE;
39 | std::unique_ptr frame_buf(new uint8_t[buf_size]);
40 |
41 | while(1)
42 | {
43 | bool end_of_frame = false;
44 | int frame_size = h265_file->ReadFrame((char*)frame_buf.get(), buf_size, &end_of_frame);
45 | //fprintf(stderr,"send stream %d bits\n", frame_size << 3);
46 |
47 | if(frame_size > 0)
48 | {
49 | xop::AVFrame videoFrame = {0};
50 | videoFrame.type = 0;
51 | videoFrame.size = frame_size;
52 | videoFrame.timestamp = xop::H265Source::GetTimestamp();
53 | videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
54 | memcpy(videoFrame.buffer.get(), frame_buf.get(), videoFrame.size);
55 | rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame);
56 | }
57 | else
58 | {
59 | fprintf(stderr, "send stream size is %d\n", frame_size);
60 | break;
61 | }
62 | xop::Timer::Sleep(40);
63 | };
64 |
65 | return;
66 | }
67 |
68 |
69 | H265File::H265File(int buf_size)
70 | : m_buf_size(buf_size)
71 | {
72 | m_buf = new char[m_buf_size];
73 | }
74 |
75 | H265File::~H265File()
76 | {
77 | delete m_buf;
78 | }
79 |
80 | bool H265File::Open(const char *path)
81 | {
82 | m_file = fopen(path, "rb");
83 | if(m_file == NULL)
84 | {
85 | return false;
86 | }
87 | return true;
88 | }
89 |
90 | void H265File::Close()
91 | {
92 | if(m_file)
93 | {
94 | fclose(m_file);
95 | m_file = NULL;
96 | m_count = 0;
97 | m_bytes_used = 0;
98 | }
99 | }
100 |
101 | int H265File::ReadFrame(char* in_buf, int in_buf_size, bool* end)
102 | {
103 | if(m_file == NULL)
104 | {
105 | return -1;
106 | }
107 |
108 | int bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file);
109 | if(bytes_read == 0)
110 | {
111 | fseek(m_file, 0, SEEK_SET);
112 | m_count = 0;
113 | m_bytes_used = 0;
114 | bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file);
115 | if(bytes_read == 0)
116 | {
117 | this->Close();
118 | return -1;
119 | }
120 | }
121 |
122 | bool is_find_start = false;
123 | bool is_find_end = false;
124 | int i = 0, start_code = 3;
125 | *end = false;
126 |
127 | int code = 0;
128 | for (i = 0; i < bytes_read - 5; i++)
129 | {
130 | if(m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 1)
131 | {
132 | start_code = 3;
133 | }
134 | else if(m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 0 && m_buf[i + 3] == 1)
135 | {
136 | start_code = 4;
137 | }
138 | else
139 | {
140 | continue;
141 | }
142 |
143 | code = m_buf[i + start_code];
144 | if (((code & 0x7E) >> 1 == 32) || ((code & 0x7E) >> 1 == 33) ||
145 | ((code & 0x7E) >> 1 == 34) || ((code & 0x7E) >> 1 == 19) ||
146 | ((code & 0x7E) >> 1 == 1) || ((code & 0x7E) >> 1 == 20) ||
147 | ((code & 0x7E) >> 1 == 39))
148 | {
149 | is_find_start = true;
150 | i += start_code;
151 | break;
152 | }
153 | }
154 |
155 | for (; i < bytes_read - 5; i++)
156 | {
157 | if(m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 1)
158 | {
159 | start_code = 3;
160 | }
161 | else if(m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 0 && m_buf[i + 3] == 1)
162 | {
163 | start_code = 4;
164 | }
165 | else
166 | {
167 | continue;
168 | }
169 |
170 | code = m_buf[i + start_code];
171 | if(((code & 0x7E) >> 1 == 32) || ((code & 0x7E) >> 1 == 33) ||
172 | ((code & 0x7E) >> 1 == 34) || ((code & 0x7E) >> 1 == 19) ||
173 | ((code & 0x7E) >> 1 == 1) || ((code & 0x7E) >> 1 == 20) ||
174 | ((code & 0x7E) >> 1 == 39))
175 | {
176 | is_find_end = true;
177 | break;
178 | }
179 | }
180 |
181 | bool flag = false;
182 | if(is_find_start && !is_find_end && m_count > 0)
183 | {
184 | flag = is_find_end = true;
185 | i = bytes_read;
186 | *end = true;
187 | }
188 |
189 | if(!is_find_start || !is_find_end)
190 | {
191 | this->Close();
192 | return -1;
193 | }
194 | int size = (i <= in_buf_size ? i : in_buf_size);
195 | memcpy(in_buf, m_buf, size);
196 |
197 | if(!flag)
198 | {
199 | m_count += 1;
200 | m_bytes_used += i;
201 | }
202 | else
203 | {
204 | m_count = 0;
205 | m_bytes_used = 0;
206 | }
207 |
208 | fseek(m_file, m_bytes_used, SEEK_SET);
209 | return size;
210 | }
211 |
212 |
213 | int test_rtsp_h265(void)
214 | {
215 | std::shared_ptr h265_server;
216 | xop::MediaSessionId h265_session_id;
217 |
218 | H265File h265_file;
219 | if (!h265_file.Open("test.h265"))
220 | {
221 | return 0;
222 | }
223 |
224 | std::string suffix = "codec2021";
225 | std::string ip = "127.0.0.1";
226 | std::string port = "554";
227 | std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;
228 |
229 | std::shared_ptr event_loop(new xop::EventLoop());
230 | h265_server = xop::RtspServer::Create(event_loop.get());
231 |
232 | if (!h265_server->Start("0.0.0.0", atoi(port.c_str()))) {
233 | printf("RTSP Server listen on %s failed.\n", port.c_str());
234 | return 0;
235 | }
236 |
237 | #ifdef AUTH_CONFIG
238 | server->SetAuthConfig("-_-", "admin", "12345");
239 | #endif
240 |
241 | xop::MediaSession* session = xop::MediaSession::CreateNew("codec2021");
242 | session->AddSource(xop::channel_0, xop::H265Source::CreateNew());
243 | //session->StartMulticast();
244 | session->SetNotifyCallback([](xop::MediaSessionId session_id, uint32_t clients) {
245 | std::cout << "The number of rtsp clients: " << clients << std::endl;
246 | });
247 |
248 | h265_session_id = h265_server->AddSession(session);
249 |
250 | std::cout << "Play URL: " << rtsp_url << std::endl;
251 |
252 | std::thread t1(SendFrameThread, h265_server.get(), h265_session_id, &h265_file);
253 |
254 | while (1)
255 | {
256 | xop::Timer::Sleep(100);
257 | }
258 |
259 | return 0;
260 | }
261 |
262 |
263 | int main(int argc, char** argv)
264 | {
265 | if(argc != 2)
266 | {
267 | printf("Usage: %s test.h265\n", argv[0]);
268 | return 0;
269 | }
270 |
271 |
272 | test_rtsp_h265();
273 |
274 | return 0;
275 | }
276 |
--------------------------------------------------------------------------------
/example/rtsp_pusher.cpp:
--------------------------------------------------------------------------------
1 | // RTSP Pusher
2 |
3 | #include "xop/RtspPusher.h"
4 | #include "net/Timer.h"
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #define PUSH_TEST "rtsp://10.11.165.203:554/test"
11 |
12 | void snedFrameThread(xop::RtspPusher* rtspPusher);
13 |
14 | int main(int argc, char **argv)
15 | {
16 | std::shared_ptr event_loop(new xop::EventLoop());
17 | std::shared_ptr rtsp_pusher = xop::RtspPusher::Create(event_loop.get());
18 |
19 | xop::MediaSession *session = xop::MediaSession::CreateNew();
20 | session->AddSource(xop::channel_0, xop::H264Source::CreateNew());
21 | session->AddSource(xop::channel_1, xop::AACSource::CreateNew(44100, 2, false));
22 | rtsp_pusher->AddSession(session);
23 |
24 | if (rtsp_pusher->OpenUrl(PUSH_TEST, 3000) < 0) {
25 | std::cout << "Open " << PUSH_TEST << " failed." << std::endl;
26 | getchar();
27 | return 0;
28 | }
29 |
30 | std::cout << "Push stream to " << PUSH_TEST << " ..." << std::endl;
31 |
32 | std::thread thread(snedFrameThread, rtsp_pusher.get());
33 | thread.detach();
34 |
35 | while (1) {
36 | xop::Timer::Sleep(100);
37 | }
38 |
39 | getchar();
40 | return 0;
41 | }
42 |
43 | void snedFrameThread(xop::RtspPusher* rtsp_pusher)
44 | {
45 | while(rtsp_pusher->IsConnected())
46 | {
47 | {
48 | /*
49 | //获取一帧 H264, 打包
50 | xop::AVFrame videoFrame = {0};
51 | //videoFrame.size = video frame size; // 视频帧大小
52 | videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 时间戳, 建议使用编码器提供的时间戳
53 | videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
54 | //memcpy(videoFrame.buffer.get(), video frame data, videoFrame.size);
55 |
56 | rtsp_pusher->PushFrame(xop::channel_0, videoFrame); //推流到服务器, 接口线程安全
57 | */
58 | }
59 |
60 | {
61 | /*
62 | //获取一帧 AAC, 打包
63 | xop::AVFrame audioFrame = {0};
64 | //audioFrame.size = audio frame size; // 音频帧大小
65 | audioFrame.timestamp = xop::AACSource::GetTimestamp(44100); // 时间戳
66 | audioFrame.buffer.reset(new uint8_t[audioFrame.size]);
67 | //memcpy(audioFrame.buffer.get(), audio frame data, audioFrame.size);
68 |
69 | rtsp_pusher->PushFrame(xop::channel_1, audioFrame); //推流到服务器, 接口线程安全
70 | */
71 | }
72 |
73 | xop::Timer::Sleep(1);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/example/rtsp_server.cpp:
--------------------------------------------------------------------------------
1 | // RTSP Server
2 |
3 | #include "xop/RtspServer.h"
4 | #include "net/Timer.h"
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, int& clients);
11 |
12 | int main(int argc, char **argv)
13 | {
14 | int clients = 0;
15 | std::string ip = "0.0.0.0";
16 | std::string rtsp_url = "rtsp://127.0.0.1:554/live";
17 |
18 | std::shared_ptr event_loop(new xop::EventLoop());
19 | std::shared_ptr server = xop::RtspServer::Create(event_loop.get());
20 | if (!server->Start(ip, 554)) {
21 | return -1;
22 | }
23 |
24 | #ifdef AUTH_CONFIG
25 | server->SetAuthConfig("-_-", "admin", "12345");
26 | #endif
27 |
28 | xop::MediaSession *session = xop::MediaSession::CreateNew("live"); // url: rtsp://ip/live
29 | session->AddSource(xop::channel_0, xop::H264Source::CreateNew());
30 | session->AddSource(xop::channel_1, xop::AACSource::CreateNew(44100,2));
31 | // session->startMulticast(); /* 开启组播(ip,端口随机生成), 默认使用 RTP_OVER_UDP, RTP_OVER_RTSP */
32 |
33 | session->SetNotifyCallback([&clients, &rtsp_url](xop::MediaSessionId session_id, uint32_t num_clients) {
34 | clients = num_clients;
35 | std::cout << "[" << rtsp_url << "]" << " Online: " << clients << std::endl;
36 | });
37 |
38 | std::cout << "URL: " << rtsp_url << std::endl;
39 |
40 | xop::MediaSessionId session_id = server->AddSession(session);
41 | //server->removeMeidaSession(session_id); /* 取消会话, 接口线程安全 */
42 |
43 | std::thread thread(SendFrameThread, server.get(), session_id, std::ref(clients));
44 | thread.detach();
45 |
46 | while(1) {
47 | xop::Timer::Sleep(100);
48 | }
49 |
50 | getchar();
51 | return 0;
52 | }
53 |
54 | void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, int& clients)
55 | {
56 | while(1)
57 | {
58 | if(clients > 0) /* 会话有客户端在线, 发送音视频数据 */
59 | {
60 | {
61 | /*
62 | //获取一帧 H264, 打包
63 | xop::AVFrame videoFrame = {0};
64 | videoFrame.type = 0; // 建议确定帧类型。I帧(xop::VIDEO_FRAME_I) P帧(xop::VIDEO_FRAME_P)
65 | videoFrame.size = video frame size; // 视频帧大小
66 | videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 时间戳, 建议使用编码器提供的时间戳
67 | videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
68 | memcpy(videoFrame.buffer.get(), video frame data, videoFrame.size);
69 |
70 | rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame); //送到服务器进行转发, 接口线程安全
71 | */
72 | }
73 |
74 | {
75 | /*
76 | //获取一帧 AAC, 打包
77 | xop::AVFrame audioFrame = {0};
78 | audioFrame.type = xop::AUDIO_FRAME;
79 | audioFrame.size = audio frame size; /* 音频帧大小
80 | audioFrame.timestamp = xop::AACSource::GetTimestamp(44100); // 时间戳
81 | audioFrame.buffer.reset(new uint8_t[audioFrame.size]);
82 | memcpy(audioFrame.buffer.get(), audio frame data, audioFrame.size);
83 |
84 | rtsp_server->PushFrame(session_id, xop::channel_1, audioFrame); // 送到服务器进行转发, 接口线程安全
85 | */
86 | }
87 | }
88 |
89 | xop::Timer::Sleep(1); /* 实际使用需要根据帧率计算延时! */
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/pic/1.pic.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codec2021/rtspServerH265/1a3d7928bc3d84cb458e34f63d49565d4a8b6f74/pic/1.pic.JPG
--------------------------------------------------------------------------------
/src/3rdpart/md5/COPYING:
--------------------------------------------------------------------------------
1 | Main Library:
2 |
3 | Copyright (c) 2014, Peter Thorson. All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | * Neither the name of the WebSocket++ Project nor the
13 | names of its contributors may be used to endorse or promote products
14 | derived from this software without specific prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
27 | Bundled Libraries:
28 |
29 | ****** Base 64 Library (base64/base64.hpp) ******
30 | base64.hpp is a repackaging of the base64.cpp and base64.h files into a
31 | single header suitable for use as a header only library. This conversion was
32 | done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to
33 | the code are redistributed under the same license as the original, which is
34 | listed below.
35 |
36 | base64.cpp and base64.h
37 |
38 | Copyright (C) 2004-2008 René Nyffenegger
39 |
40 | This source code is provided 'as-is', without any express or implied
41 | warranty. In no event will the author be held liable for any damages
42 | arising from the use of this software.
43 |
44 | Permission is granted to anyone to use this software for any purpose,
45 | including commercial applications, and to alter it and redistribute it
46 | freely, subject to the following restrictions:
47 |
48 | 1. The origin of this source code must not be misrepresented; you must not
49 | claim that you wrote the original source code. If you use this source code
50 | in a product, an acknowledgment in the product documentation would be
51 | appreciated but is not required.
52 |
53 | 2. Altered source versions must be plainly marked as such, and must not be
54 | misrepresented as being the original source code.
55 |
56 | 3. This notice may not be removed or altered from any source distribution.
57 |
58 | René Nyffenegger rene.nyffenegger@adp-gmbh.ch
59 |
60 | ****** SHA1 Library (sha1/sha1.hpp) ******
61 | sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1
62 | library (http://code.google.com/p/smallsha1/) into a single header suitable for
63 | use as a header only library. This conversion was done by Peter Thorson
64 | (webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed
65 | under the same license as the original, which is listed below.
66 |
67 | Copyright (c) 2011, Micael Hildenborg
68 | All rights reserved.
69 |
70 | Redistribution and use in source and binary forms, with or without
71 | modification, are permitted provided that the following conditions are met:
72 | * Redistributions of source code must retain the above copyright
73 | notice, this list of conditions and the following disclaimer.
74 | * Redistributions in binary form must reproduce the above copyright
75 | notice, this list of conditions and the following disclaimer in the
76 | documentation and/or other materials provided with the distribution.
77 | * Neither the name of Micael Hildenborg nor the
78 | names of its contributors may be used to endorse or promote products
79 | derived from this software without specific prior written permission.
80 |
81 | THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
82 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
83 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
84 | DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
85 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
86 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
87 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
88 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
89 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
90 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91 |
92 | ****** MD5 Library (common/md5.hpp) ******
93 | md5.hpp is a reformulation of the md5.h and md5.c code from
94 | http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to
95 | function as a component of a header only library. This conversion was done by
96 | Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The
97 | changes are released under the same license as the original (listed below)
98 |
99 | Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
100 |
101 | This software is provided 'as-is', without any express or implied
102 | warranty. In no event will the authors be held liable for any damages
103 | arising from the use of this software.
104 |
105 | Permission is granted to anyone to use this software for any purpose,
106 | including commercial applications, and to alter it and redistribute it
107 | freely, subject to the following restrictions:
108 |
109 | 1. The origin of this software must not be misrepresented; you must not
110 | claim that you wrote the original software. If you use this software
111 | in a product, an acknowledgment in the product documentation would be
112 | appreciated but is not required.
113 | 2. Altered source versions must be plainly marked as such, and must not be
114 | misrepresented as being the original software.
115 | 3. This notice may not be removed or altered from any source distribution.
116 |
117 | L. Peter Deutsch
118 | ghost@aladdin.com
119 |
120 | ****** UTF8 Validation logic (utf8_validation.hpp) ******
121 | utf8_validation.hpp is adapted from code originally written by Bjoern Hoehrmann
122 | . See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for
123 | details.
124 |
125 | The original license:
126 |
127 | Copyright (c) 2008-2009 Bjoern Hoehrmann
128 |
129 | Permission is hereby granted, free of charge, to any person obtaining a copy
130 | of this software and associated documentation files (the "Software"), to deal
131 | in the Software without restriction, including without limitation the rights
132 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
133 | copies of the Software, and to permit persons to whom the Software is
134 | furnished to do so, subject to the following conditions:
135 |
136 | The above copyright notice and this permission notice shall be included in
137 | all copies or substantial portions of the Software.
138 |
139 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
140 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
141 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
142 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
143 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
144 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
145 | SOFTWARE.
146 |
--------------------------------------------------------------------------------
/src/net/Acceptor.cpp:
--------------------------------------------------------------------------------
1 | #include "Acceptor.h"
2 | #include "EventLoop.h"
3 | #include "SocketUtil.h"
4 | #include "Logger.h"
5 |
6 | using namespace xop;
7 |
8 | Acceptor::Acceptor(EventLoop* eventLoop)
9 | : event_loop_(eventLoop)
10 | , tcp_socket_(new TcpSocket)
11 | {
12 |
13 | }
14 |
15 | Acceptor::~Acceptor()
16 | {
17 |
18 | }
19 |
20 | int Acceptor::Listen(std::string ip, uint16_t port)
21 | {
22 | std::lock_guard locker(mutex_);
23 |
24 | if (tcp_socket_->GetSocket() > 0) {
25 | tcp_socket_->Close();
26 | }
27 |
28 | SOCKET sockfd = tcp_socket_->Create();
29 | channel_ptr_.reset(new Channel(sockfd));
30 | SocketUtil::SetReuseAddr(sockfd);
31 | SocketUtil::SetReusePort(sockfd);
32 | SocketUtil::SetNonBlock(sockfd);
33 |
34 | if (!tcp_socket_->Bind(ip, port)) {
35 | return -1;
36 | }
37 |
38 | if (!tcp_socket_->Listen(1024)) {
39 | return -1;
40 | }
41 |
42 | channel_ptr_->SetReadCallback([this]() { this->OnAccept(); });
43 | channel_ptr_->EnableReading();
44 | event_loop_->UpdateChannel(channel_ptr_);
45 | return 0;
46 | }
47 |
48 | void Acceptor::Close()
49 | {
50 | std::lock_guard locker(mutex_);
51 |
52 | if (tcp_socket_->GetSocket() > 0) {
53 | event_loop_->RemoveChannel(channel_ptr_);
54 | tcp_socket_->Close();
55 | }
56 | }
57 |
58 | void Acceptor::OnAccept()
59 | {
60 | std::lock_guard locker(mutex_);
61 |
62 | SOCKET connfd = tcp_socket_->Accept();
63 | if (connfd > 0) {
64 | if (new_connection_callback_) {
65 | new_connection_callback_(connfd);
66 | }
67 | else {
68 | SocketUtil::Close(connfd);
69 | }
70 | }
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/src/net/Acceptor.h:
--------------------------------------------------------------------------------
1 | #ifndef XOP_ACCEPTOR_H
2 | #define XOP_ACCEPTOR_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include "Channel.h"
8 | #include "TcpSocket.h"
9 |
10 | namespace xop
11 | {
12 |
13 | typedef std::function NewConnectionCallback;
14 |
15 | class EventLoop;
16 |
17 | class Acceptor
18 | {
19 | public:
20 | Acceptor(EventLoop* eventLoop);
21 | ~Acceptor();
22 |
23 | void SetNewConnectionCallback(const NewConnectionCallback& cb)
24 | { new_connection_callback_ = cb; }
25 |
26 | int Listen(std::string ip, uint16_t port);
27 | void Close();
28 |
29 | private:
30 | void OnAccept();
31 |
32 | EventLoop* event_loop_ = nullptr;
33 | std::mutex mutex_;
34 | std::unique_ptr tcp_socket_;
35 | ChannelPtr channel_ptr_;
36 | NewConnectionCallback new_connection_callback_;
37 | };
38 |
39 | }
40 |
41 | #endif
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/net/BufferReader.cpp:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #include "BufferReader.h"
5 | #include "Socket.h"
6 | #include
7 |
8 | using namespace xop;
9 | uint32_t xop::ReadUint32BE(char* data)
10 | {
11 | uint8_t* p = (uint8_t*)data;
12 | uint32_t value = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
13 | return value;
14 | }
15 |
16 | uint32_t xop::ReadUint32LE(char* data)
17 | {
18 | uint8_t* p = (uint8_t*)data;
19 | uint32_t value = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
20 | return value;
21 | }
22 |
23 | uint32_t xop::ReadUint24BE(char* data)
24 | {
25 | uint8_t* p = (uint8_t*)data;
26 | uint32_t value = (p[0] << 16) | (p[1] << 8) | p[2];
27 | return value;
28 | }
29 |
30 | uint32_t xop::ReadUint24LE(char* data)
31 | {
32 | uint8_t* p = (uint8_t*)data;
33 | uint32_t value = (p[2] << 16) | (p[1] << 8) | p[0];
34 | return value;
35 | }
36 |
37 | uint16_t xop::ReadUint16BE(char* data)
38 | {
39 | uint8_t* p = (uint8_t*)data;
40 | uint16_t value = (p[0] << 8) | p[1];
41 | return value;
42 | }
43 |
44 | uint16_t xop::ReadUint16LE(char* data)
45 | {
46 | uint8_t* p = (uint8_t*)data;
47 | uint16_t value = (p[1] << 8) | p[0];
48 | return value;
49 | }
50 |
51 | const char BufferReader::kCRLF[] = "\r\n";
52 |
53 | BufferReader::BufferReader(uint32_t initialSize)
54 | : buffer_(new std::vector(initialSize))
55 | {
56 | buffer_->resize(initialSize);
57 | }
58 |
59 | BufferReader::~BufferReader()
60 | {
61 |
62 | }
63 |
64 | int BufferReader::Read(SOCKET sockfd)
65 | {
66 | uint32_t size = WritableBytes();
67 | if(size < MAX_BYTES_PER_READ) {
68 | uint32_t bufferReaderSize = (uint32_t)buffer_->size();
69 | if(bufferReaderSize > MAX_BUFFER_SIZE) {
70 | return 0;
71 | }
72 |
73 | buffer_->resize(bufferReaderSize + MAX_BYTES_PER_READ);
74 | }
75 |
76 | int bytes_read = ::recv(sockfd, beginWrite(), MAX_BYTES_PER_READ, 0);
77 | if(bytes_read > 0) {
78 | writer_index_ += bytes_read;
79 | }
80 |
81 | return bytes_read;
82 | }
83 |
84 |
85 | uint32_t BufferReader::ReadAll(std::string& data)
86 | {
87 | uint32_t size = ReadableBytes();
88 | if(size > 0) {
89 | data.assign(Peek(), size);
90 | writer_index_ = 0;
91 | reader_index_ = 0;
92 | }
93 |
94 | return size;
95 | }
96 |
97 | uint32_t BufferReader::ReadUntilCrlf(std::string& data)
98 | {
99 | const char* crlf = FindLastCrlf();
100 | if(crlf == nullptr) {
101 | return 0;
102 | }
103 |
104 | uint32_t size = (uint32_t)(crlf - Peek() + 2);
105 | data.assign(Peek(), size);
106 | Retrieve(size);
107 | return size;
108 | }
109 |
110 |
--------------------------------------------------------------------------------
/src/net/BufferReader.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_BUFFER_READER_H
5 | #define XOP_BUFFER_READER_H
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include "Socket.h"
13 |
14 | namespace xop
15 | {
16 |
17 | uint32_t ReadUint32BE(char* data);
18 | uint32_t ReadUint32LE(char* data);
19 | uint32_t ReadUint24BE(char* data);
20 | uint32_t ReadUint24LE(char* data);
21 | uint16_t ReadUint16BE(char* data);
22 | uint16_t ReadUint16LE(char* data);
23 |
24 | class BufferReader
25 | {
26 | public:
27 | static const uint32_t kInitialSize = 2048;
28 | BufferReader(uint32_t initialSize = kInitialSize);
29 | virtual ~BufferReader();
30 |
31 | uint32_t ReadableBytes() const
32 | { return (uint32_t)(writer_index_ - reader_index_); }
33 |
34 | uint32_t WritableBytes() const
35 | { return (uint32_t)(buffer_->size() - writer_index_); }
36 |
37 | char* Peek()
38 | { return Begin() + reader_index_; }
39 |
40 | const char* Peek() const
41 | { return Begin() + reader_index_; }
42 |
43 | const char* FindFirstCrlf() const {
44 | const char* crlf = std::search(Peek(), BeginWrite(), kCRLF, kCRLF+2);
45 | return crlf == BeginWrite() ? nullptr : crlf;
46 | }
47 |
48 | const char* FindLastCrlf() const {
49 | const char* crlf = std::find_end(Peek(), BeginWrite(), kCRLF, kCRLF+2);
50 | return crlf == BeginWrite() ? nullptr : crlf;
51 | }
52 |
53 | const char* FindLastCrlfCrlf() const {
54 | char crlfCrlf[] = "\r\n\r\n";
55 | const char* crlf = std::find_end(Peek(), BeginWrite(), crlfCrlf, crlfCrlf + 4);
56 | return crlf == BeginWrite() ? nullptr : crlf;
57 | }
58 |
59 | void RetrieveAll() {
60 | writer_index_ = 0;
61 | reader_index_ = 0;
62 | }
63 |
64 | void Retrieve(size_t len) {
65 | if (len <= ReadableBytes()) {
66 | reader_index_ += len;
67 | if(reader_index_ == writer_index_) {
68 | reader_index_ = 0;
69 | writer_index_ = 0;
70 | }
71 | }
72 | else {
73 | RetrieveAll();
74 | }
75 | }
76 |
77 | void RetrieveUntil(const char* end)
78 | { Retrieve(end - Peek()); }
79 |
80 | int Read(SOCKET sockfd);
81 | uint32_t ReadAll(std::string& data);
82 | uint32_t ReadUntilCrlf(std::string& data);
83 |
84 | uint32_t Size() const
85 | { return (uint32_t)buffer_->size(); }
86 |
87 | private:
88 | char* Begin()
89 | { return &*buffer_->begin(); }
90 |
91 | const char* Begin() const
92 | { return &*buffer_->begin(); }
93 |
94 | char* beginWrite()
95 | { return Begin() + writer_index_; }
96 |
97 | const char* BeginWrite() const
98 | { return Begin() + writer_index_; }
99 |
100 | std::shared_ptr> buffer_;
101 | size_t reader_index_ = 0;
102 | size_t writer_index_ = 0;
103 |
104 | static const char kCRLF[];
105 | static const uint32_t MAX_BYTES_PER_READ = 4096;
106 | static const uint32_t MAX_BUFFER_SIZE = 1024 * 100000;
107 | };
108 |
109 | }
110 |
111 | #endif
112 |
113 |
114 |
--------------------------------------------------------------------------------
/src/net/BufferWriter.cpp:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #include "BufferWriter.h"
5 | #include "Socket.h"
6 | #include "SocketUtil.h"
7 |
8 | using namespace xop;
9 |
10 | void xop::WriteUint32BE(char* p, uint32_t value)
11 | {
12 | p[0] = value >> 24;
13 | p[1] = value >> 16;
14 | p[2] = value >> 8;
15 | p[3] = value & 0xff;
16 | }
17 |
18 | void xop::WriteUint32LE(char* p, uint32_t value)
19 | {
20 | p[0] = value & 0xff;
21 | p[1] = value >> 8;
22 | p[2] = value >> 16;
23 | p[3] = value >> 24;
24 | }
25 |
26 | void xop::WriteUint24BE(char* p, uint32_t value)
27 | {
28 | p[0] = value >> 16;
29 | p[1] = value >> 8;
30 | p[2] = value & 0xff;
31 | }
32 |
33 | void xop::WriteUint24LE(char* p, uint32_t value)
34 | {
35 | p[0] = value & 0xff;
36 | p[1] = value >> 8;
37 | p[2] = value >> 16;
38 | }
39 |
40 | void xop::WriteUint16BE(char* p, uint16_t value)
41 | {
42 | p[0] = value >> 8;
43 | p[1] = value & 0xff;
44 | }
45 |
46 | void xop::WriteUint16LE(char* p, uint16_t value)
47 | {
48 | p[0] = value & 0xff;
49 | p[1] = value >> 8;
50 | }
51 |
52 | BufferWriter::BufferWriter(int capacity)
53 | : max_queue_length_(capacity)
54 | , buffer_(new std::queue)
55 | {
56 |
57 | }
58 |
59 | bool BufferWriter::Append(std::shared_ptr data, uint32_t size, uint32_t index)
60 | {
61 | if (size <= index) {
62 | return false;
63 | }
64 |
65 | if ((int)buffer_->size() >= max_queue_length_) {
66 | return false;
67 | }
68 |
69 | Packet pkt = {data, size, index};
70 | buffer_->emplace(std::move(pkt));
71 | return true;
72 | }
73 |
74 | bool BufferWriter::Append(const char* data, uint32_t size, uint32_t index)
75 | {
76 | if (size <= index) {
77 | return false;
78 | }
79 |
80 | if ((int)buffer_->size() >= max_queue_length_) {
81 | return false;
82 | }
83 |
84 | Packet pkt;
85 | pkt.data.reset(new char[size+512]);
86 | memcpy(pkt.data.get(), data, size);
87 | pkt.size = size;
88 | pkt.writeIndex = index;
89 | buffer_->emplace(std::move(pkt));
90 | return true;
91 | }
92 |
93 | int BufferWriter::Send(SOCKET sockfd, int timeout)
94 | {
95 | if (timeout > 0) {
96 | SocketUtil::SetBlock(sockfd, timeout);
97 | }
98 |
99 | int ret = 0;
100 | int count = 1;
101 |
102 | do
103 | {
104 | if (buffer_->empty()) {
105 | return 0;
106 | }
107 |
108 | count -= 1;
109 | Packet &pkt = buffer_->front();
110 | ret = ::send(sockfd, pkt.data.get() + pkt.writeIndex, pkt.size - pkt.writeIndex, 0);
111 | if (ret > 0) {
112 | pkt.writeIndex += ret;
113 | if (pkt.size == pkt.writeIndex) {
114 | count += 1;
115 | buffer_->pop();
116 | }
117 | }
118 | else if (ret < 0) {
119 | #if defined(__linux) || defined(__linux__)
120 | if (errno == EINTR || errno == EAGAIN)
121 | #elif defined(WIN32) || defined(_WIN32)
122 | int error = WSAGetLastError();
123 | if (error == WSAEWOULDBLOCK || error == WSAEINPROGRESS || error == 0)
124 | #endif
125 | {
126 | ret = 0;
127 | }
128 | }
129 | } while (count > 0);
130 |
131 | if (timeout > 0) {
132 | SocketUtil::SetNonBlock(sockfd);
133 | }
134 |
135 | return ret;
136 | }
137 |
138 |
139 |
--------------------------------------------------------------------------------
/src/net/BufferWriter.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_BUFFER_WRITER_H
5 | #define XOP_BUFFER_WRITER_H
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "Socket.h"
12 |
13 | namespace xop
14 | {
15 |
16 | void WriteUint32BE(char* p, uint32_t value);
17 | void WriteUint32LE(char* p, uint32_t value);
18 | void WriteUint24BE(char* p, uint32_t value);
19 | void WriteUint24LE(char* p, uint32_t value);
20 | void WriteUint16BE(char* p, uint16_t value);
21 | void WriteUint16LE(char* p, uint16_t value);
22 |
23 | class BufferWriter
24 | {
25 | public:
26 | BufferWriter(int capacity = kMaxQueueLength);
27 | ~BufferWriter() {}
28 |
29 | bool Append(std::shared_ptr data, uint32_t size, uint32_t index=0);
30 | bool Append(const char* data, uint32_t size, uint32_t index=0);
31 | int Send(SOCKET sockfd, int timeout=0);
32 |
33 | bool IsEmpty() const
34 | { return buffer_->empty(); }
35 |
36 | bool IsFull() const
37 | { return ((int)buffer_->size() >= max_queue_length_ ? true : false); }
38 |
39 | uint32_t Size() const
40 | { return (uint32_t)buffer_->size(); }
41 |
42 | private:
43 | typedef struct
44 | {
45 | std::shared_ptr data;
46 | uint32_t size;
47 | uint32_t writeIndex;
48 | } Packet;
49 |
50 | std::shared_ptr> buffer_;
51 | int max_queue_length_ = 0;
52 |
53 | static const int kMaxQueueLength = 10000;
54 | };
55 |
56 | }
57 |
58 | #endif
59 |
60 |
--------------------------------------------------------------------------------
/src/net/Channel.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_CHANNEL_H
5 | #define XOP_CHANNEL_H
6 |
7 | #include
8 | #include
9 | #include "Socket.h"
10 |
11 | namespace xop
12 | {
13 |
14 | enum EventType
15 | {
16 | EVENT_NONE = 0,
17 | EVENT_IN = 1,
18 | EVENT_PRI = 2,
19 | EVENT_OUT = 4,
20 | EVENT_ERR = 8,
21 | EVENT_HUP = 16,
22 | EVENT_RDHUP = 8192
23 | };
24 |
25 | class Channel
26 | {
27 | public:
28 | typedef std::function EventCallback;
29 |
30 | Channel() = delete;
31 | Channel(SOCKET sockfd) : sockfd_(sockfd) {};
32 | virtual ~Channel() {};
33 |
34 | void SetReadCallback(const EventCallback& cb)
35 | { read_callback_ = cb; }
36 |
37 | void SetWriteCallback(const EventCallback& cb)
38 | { write_callback_ = cb; }
39 |
40 | void SetCloseCallback(const EventCallback& cb)
41 | { close_callback_ = cb; }
42 |
43 | void SetErrorCallback(const EventCallback& cb)
44 | { error_callback_ = cb; }
45 |
46 | SOCKET GetSocket() const { return sockfd_; }
47 |
48 | int GetEvents() const { return events_; }
49 | void SetEvents(int events) { events_ = events; }
50 |
51 | void EnableReading()
52 | { events_ |= EVENT_IN; }
53 |
54 | void EnableWriting()
55 | { events_ |= EVENT_OUT; }
56 |
57 | void DisableReading()
58 | { events_ &= ~EVENT_IN; }
59 |
60 | void DisableWriting()
61 | { events_ &= ~EVENT_OUT; }
62 |
63 | bool IsNoneEvent() const { return events_ == EVENT_NONE; }
64 | bool IsWriting() const { return (events_ & EVENT_OUT) != 0; }
65 | bool IsReading() const { return (events_ & EVENT_IN) != 0; }
66 |
67 | void HandleEvent(int events)
68 | {
69 | if (events & (EVENT_PRI | EVENT_IN)) {
70 | read_callback_();
71 | }
72 |
73 | if (events & EVENT_OUT) {
74 | write_callback_();
75 | }
76 |
77 | if (events & EVENT_HUP) {
78 | close_callback_();
79 | return ;
80 | }
81 |
82 | if (events & (EVENT_ERR)) {
83 | error_callback_();
84 | }
85 | }
86 |
87 | private:
88 | EventCallback read_callback_ = []{};
89 | EventCallback write_callback_ = []{};
90 | EventCallback close_callback_ = []{};
91 | EventCallback error_callback_ = []{};
92 |
93 | SOCKET sockfd_ = 0;
94 | int events_ = 0;
95 | };
96 |
97 | typedef std::shared_ptr ChannelPtr;
98 |
99 | }
100 |
101 | #endif
102 |
103 |
--------------------------------------------------------------------------------
/src/net/EpollTaskScheduler.cpp:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #include "EpollTaskScheduler.h"
5 |
6 | #if defined(__linux) || defined(__linux__)
7 | #include
8 | #include
9 | #endif
10 |
11 | using namespace xop;
12 |
13 | EpollTaskScheduler::EpollTaskScheduler(int id)
14 | : TaskScheduler(id)
15 | {
16 | #if defined(__linux) || defined(__linux__)
17 | epollfd_ = epoll_create1(0);
18 | #endif
19 | this->UpdateChannel(wakeup_channel_);
20 | }
21 |
22 | EpollTaskScheduler::~EpollTaskScheduler()
23 | {
24 |
25 | }
26 |
27 | void EpollTaskScheduler::UpdateChannel(ChannelPtr channel)
28 | {
29 | std::lock_guard lock(mutex_);
30 | #if defined(__linux) || defined(__linux__)
31 | int fd = channel->GetSocket();
32 | if(channels_.find(fd) != channels_.end()) {
33 | if(channel->IsNoneEvent()) {
34 | Update(EPOLL_CTL_DEL, channel);
35 | channels_.erase(fd);
36 | }
37 | else {
38 | Update(EPOLL_CTL_MOD, channel);
39 | }
40 | }
41 | else {
42 | if(!channel->IsNoneEvent()) {
43 | channels_.emplace(fd, channel);
44 | Update(EPOLL_CTL_ADD, channel);
45 | }
46 | }
47 | #endif
48 | }
49 |
50 | void EpollTaskScheduler::Update(int operation, ChannelPtr& channel)
51 | {
52 | #if defined(__linux) || defined(__linux__)
53 | struct epoll_event event = {0};
54 |
55 | if(operation != EPOLL_CTL_DEL) {
56 | event.data.ptr = channel.get();
57 | event.events = channel->GetEvents();
58 | }
59 |
60 | if(::epoll_ctl(epollfd_, operation, channel->GetSocket(), &event) < 0) {
61 |
62 | }
63 | #endif
64 | }
65 |
66 | void EpollTaskScheduler::RemoveChannel(ChannelPtr& channel)
67 | {
68 | std::lock_guard lock(mutex_);
69 | #if defined(__linux) || defined(__linux__)
70 | int fd = channel->GetSocket();
71 |
72 | if(channels_.find(fd) != channels_.end()) {
73 | Update(EPOLL_CTL_DEL, channel);
74 | channels_.erase(fd);
75 | }
76 | #endif
77 | }
78 |
79 | bool EpollTaskScheduler::HandleEvent(int timeout)
80 | {
81 | #if defined(__linux) || defined(__linux__)
82 | struct epoll_event events[512] = {0};
83 | int num_events = -1;
84 |
85 | num_events = epoll_wait(epollfd_, events, 512, timeout);
86 | if(num_events < 0) {
87 | if(errno != EINTR) {
88 | return false;
89 | }
90 | }
91 |
92 | for(int n=0; nHandleEvent(events[n].events);
95 | }
96 | }
97 | return true;
98 | #else
99 | return false;
100 | #endif
101 | }
102 |
103 |
104 |
--------------------------------------------------------------------------------
/src/net/EpollTaskScheduler.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_EPOLL_TASK_SCHEDULER_H
5 | #define XOP_EPOLL_TASK_SCHEDULER_H
6 |
7 | #include "TaskScheduler.h"
8 | #include
9 | #include
10 |
11 | namespace xop
12 | {
13 | class EpollTaskScheduler : public TaskScheduler
14 | {
15 | public:
16 | EpollTaskScheduler(int id = 0);
17 | virtual ~EpollTaskScheduler();
18 |
19 | void UpdateChannel(ChannelPtr channel);
20 | void RemoveChannel(ChannelPtr& channel);
21 |
22 | // timeout: ms
23 | bool HandleEvent(int timeout);
24 |
25 | private:
26 | void Update(int operation, ChannelPtr& channel);
27 |
28 | int epollfd_ = -1;
29 | std::mutex mutex_;
30 | std::unordered_map channels_;
31 | };
32 |
33 | }
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/src/net/EventLoop.cpp:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2019-10-18
3 |
4 | #include "EventLoop.h"
5 |
6 | #if defined(WIN32) || defined(_WIN32)
7 | #include
8 | #endif
9 |
10 | #if defined(WIN32) || defined(_WIN32)
11 | #pragma comment(lib, "Ws2_32.lib")
12 | #pragma comment(lib,"Iphlpapi.lib")
13 | #endif
14 |
15 | using namespace xop;
16 |
17 | EventLoop::EventLoop(uint32_t num_threads)
18 | : index_(1)
19 | {
20 | num_threads_ = 1;
21 | if (num_threads > 0) {
22 | num_threads_ = num_threads;
23 | }
24 |
25 | this->Loop();
26 | }
27 |
28 | EventLoop::~EventLoop()
29 | {
30 | this->Quit();
31 | }
32 |
33 | std::shared_ptr EventLoop::GetTaskScheduler()
34 | {
35 | std::lock_guard locker(mutex_);
36 | if (task_schedulers_.size() == 1) {
37 | return task_schedulers_.at(0);
38 | }
39 | else {
40 | auto task_scheduler = task_schedulers_.at(index_);
41 | index_++;
42 | if (index_ >= task_schedulers_.size()) {
43 | index_ = 1;
44 | }
45 | return task_scheduler;
46 | }
47 |
48 | return nullptr;
49 | }
50 |
51 | void EventLoop::Loop()
52 | {
53 | std::lock_guard locker(mutex_);
54 |
55 | if (!task_schedulers_.empty()) {
56 | return ;
57 | }
58 |
59 | for (uint32_t n = 0; n < num_threads_; n++)
60 | {
61 | #if defined(__linux) || defined(__linux__)
62 | std::shared_ptr task_scheduler_ptr(new EpollTaskScheduler(n));
63 | #elif defined(WIN32) || defined(_WIN32)
64 | std::shared_ptr task_scheduler_ptr(new SelectTaskScheduler(n));
65 | #endif
66 | task_schedulers_.push_back(task_scheduler_ptr);
67 | std::shared_ptr thread(new std::thread(&TaskScheduler::Start, task_scheduler_ptr.get()));
68 | thread->native_handle();
69 | threads_.push_back(thread);
70 | }
71 |
72 | int priority = TASK_SCHEDULER_PRIORITY_REALTIME;
73 |
74 | for (auto iter : threads_)
75 | {
76 | #if defined(__linux) || defined(__linux__)
77 |
78 | #elif defined(WIN32) || defined(_WIN32)
79 | switch (priority)
80 | {
81 | case TASK_SCHEDULER_PRIORITY_LOW:
82 | SetThreadPriority(iter->native_handle(), THREAD_PRIORITY_BELOW_NORMAL);
83 | break;
84 | case TASK_SCHEDULER_PRIORITY_NORMAL:
85 | SetThreadPriority(iter->native_handle(), THREAD_PRIORITY_NORMAL);
86 | break;
87 | case TASK_SCHEDULER_PRIORITYO_HIGH:
88 | SetThreadPriority(iter->native_handle(), THREAD_PRIORITY_ABOVE_NORMAL);
89 | break;
90 | case TASK_SCHEDULER_PRIORITY_HIGHEST:
91 | SetThreadPriority(iter->native_handle(), THREAD_PRIORITY_HIGHEST);
92 | break;
93 | case TASK_SCHEDULER_PRIORITY_REALTIME:
94 | SetThreadPriority(iter->native_handle(), THREAD_PRIORITY_TIME_CRITICAL);
95 | break;
96 | }
97 | #endif
98 | }
99 | }
100 |
101 | void EventLoop::Quit()
102 | {
103 | std::lock_guard locker(mutex_);
104 |
105 | for (auto iter : task_schedulers_) {
106 | iter->Stop();
107 | }
108 |
109 | for (auto iter : threads_) {
110 | iter->join();
111 | }
112 |
113 | task_schedulers_.clear();
114 | threads_.clear();
115 | }
116 |
117 | void EventLoop::UpdateChannel(ChannelPtr channel)
118 | {
119 | std::lock_guard locker(mutex_);
120 | if (task_schedulers_.size() > 0) {
121 | task_schedulers_[0]->UpdateChannel(channel);
122 | }
123 | }
124 |
125 | void EventLoop::RemoveChannel(ChannelPtr& channel)
126 | {
127 | std::lock_guard locker(mutex_);
128 | if (task_schedulers_.size() > 0) {
129 | task_schedulers_[0]->RemoveChannel(channel);
130 | }
131 | }
132 |
133 | TimerId EventLoop::AddTimer(TimerEvent timerEvent, uint32_t msec)
134 | {
135 | std::lock_guard locker(mutex_);
136 | if (task_schedulers_.size() > 0) {
137 | return task_schedulers_[0]->AddTimer(timerEvent, msec);
138 | }
139 | return 0;
140 | }
141 |
142 | void EventLoop::RemoveTimer(TimerId timerId)
143 | {
144 | std::lock_guard locker(mutex_);
145 | if (task_schedulers_.size() > 0) {
146 | task_schedulers_[0]->RemoveTimer(timerId);
147 | }
148 | }
149 |
150 | bool EventLoop::AddTriggerEvent(TriggerEvent callback)
151 | {
152 | std::lock_guard locker(mutex_);
153 | if (task_schedulers_.size() > 0) {
154 | return task_schedulers_[0]->AddTriggerEvent(callback);
155 | }
156 | return false;
157 | }
158 |
--------------------------------------------------------------------------------
/src/net/EventLoop.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_EVENT_LOOP_H
5 | #define XOP_EVENT_LOOP_H
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include "SelectTaskScheduler.h"
16 | #include "EpollTaskScheduler.h"
17 | #include "Pipe.h"
18 | #include "Timer.h"
19 | #include "RingBuffer.h"
20 |
21 | #define TASK_SCHEDULER_PRIORITY_LOW 0
22 | #define TASK_SCHEDULER_PRIORITY_NORMAL 1
23 | #define TASK_SCHEDULER_PRIORITYO_HIGH 2
24 | #define TASK_SCHEDULER_PRIORITY_HIGHEST 3
25 | #define TASK_SCHEDULER_PRIORITY_REALTIME 4
26 |
27 | namespace xop
28 | {
29 |
30 | class EventLoop
31 | {
32 | public:
33 | EventLoop(const EventLoop&) = delete;
34 | EventLoop &operator = (const EventLoop&) = delete;
35 | EventLoop(uint32_t num_threads =1); //std::thread::hardware_concurrency()
36 | virtual ~EventLoop();
37 |
38 | std::shared_ptr GetTaskScheduler();
39 |
40 | bool AddTriggerEvent(TriggerEvent callback);
41 | TimerId AddTimer(TimerEvent timerEvent, uint32_t msec);
42 | void RemoveTimer(TimerId timerId);
43 | void UpdateChannel(ChannelPtr channel);
44 | void RemoveChannel(ChannelPtr& channel);
45 |
46 | void Loop();
47 | void Quit();
48 |
49 | private:
50 | std::mutex mutex_;
51 | uint32_t num_threads_ = 1;
52 | uint32_t index_ = 1;
53 | std::vector> task_schedulers_;
54 | std::vector> threads_;
55 | };
56 |
57 | }
58 |
59 | #endif
60 |
61 |
--------------------------------------------------------------------------------
/src/net/Logger.cpp:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #if defined(WIN32) || defined(_WIN32)
5 | #ifndef _CRT_SECURE_NO_WARNINGS
6 | #define _CRT_SECURE_NO_WARNINGS
7 | #endif
8 | #endif
9 |
10 | #include "Logger.h"
11 | #include
12 | #include
13 | #include "Timestamp.h"
14 |
15 | using namespace xop;
16 |
17 | const char* Priority_To_String[] =
18 | {
19 | "DEBUG",
20 | "CONFIG",
21 | "INFO",
22 | "WARNING",
23 | "ERROR"
24 | };
25 |
26 | Logger::Logger()
27 | {
28 |
29 | }
30 |
31 | Logger& Logger::instance()
32 | {
33 | static Logger s_logger;
34 | return s_logger;
35 | }
36 |
37 | Logger::~Logger()
38 | {
39 |
40 | }
41 |
42 | void Logger::init(char *pathname)
43 | {
44 | std::unique_lock lock(_mutex);
45 |
46 | if (pathname != nullptr)
47 | {
48 | _ofs.open(pathname, std::ios::out | std::ios::binary);
49 | if (_ofs.fail())
50 | {
51 | std::cerr << "Failed to open logfile." << std::endl;
52 | }
53 | }
54 | }
55 |
56 | void Logger::exit()
57 | {
58 | std::unique_lock lock(_mutex);
59 |
60 | if (_ofs.is_open())
61 | {
62 | _ofs.close();
63 | }
64 | }
65 |
66 | void Logger::log(Priority priority, const char* __file, const char* __func, int __line, const char *fmt, ...)
67 | {
68 | std::unique_lock lock(_mutex);
69 |
70 | char buf[2048] = {0};
71 | sprintf(buf, "[%s][%s:%s:%d] ", Priority_To_String[priority], __file, __func, __line);
72 | va_list args;
73 | va_start(args, fmt);
74 | vsprintf(buf + strlen(buf), fmt, args);
75 | va_end(args);
76 |
77 | write(std::string(buf));
78 | }
79 |
80 | void Logger::log2(Priority priority, const char *fmt, ...)
81 | {
82 | std::unique_lock lock(_mutex);
83 |
84 | char buf[4096] = { 0 };
85 | sprintf(buf, "[%s] ", Priority_To_String[priority]);
86 | va_list args;
87 | va_start(args, fmt);
88 | vsprintf(buf + strlen(buf), fmt, args);
89 | va_end(args);
90 |
91 | write(std::string(buf));
92 | }
93 |
94 | void Logger::write(std::string info)
95 | {
96 | if (_ofs.is_open())
97 | {
98 | _ofs << "[" << Timestamp::localtime() << "]"
99 | << info << std::endl;
100 | }
101 |
102 | std::cout << "[" << Timestamp::localtime() << "]"
103 | << info << std::endl;
104 | }
105 |
--------------------------------------------------------------------------------
/src/net/Logger.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2020-5-15
3 |
4 | #ifndef XOP_LOGGER_H
5 | #define XOP_LOGGER_H
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | namespace xop {
16 |
17 |
18 | enum Priority
19 | {
20 | LOG_DEBUG, LOG_STATE, LOG_INFO, LOG_WARNING, LOG_ERROR,
21 | };
22 |
23 | class Logger
24 | {
25 | public:
26 | Logger &operator=(const Logger &) = delete;
27 | Logger(const Logger &) = delete;
28 | static Logger& instance();
29 | ~Logger();
30 |
31 | void init(char *pathname = nullptr);
32 | void exit();
33 |
34 | void log(Priority priority, const char* __file, const char* __func, int __line, const char *fmt, ...);
35 | void log2(Priority priority, const char *fmt, ...);
36 |
37 | private:
38 | void write(std::string buf);
39 | Logger();
40 |
41 | std::mutex _mutex;
42 | std::ofstream _ofs;
43 | };
44 |
45 | }
46 |
47 | #ifdef _DEBUG
48 | #define LOG_DEBUG(fmt, ...) xop::Logger::instance().log(LOG_DEBUG, __FILE__, __FUNCTION__,__LINE__, fmt, ##__VA_ARGS__)
49 | #else
50 | #define LOG_DEBUG(fmt, ...)
51 | #endif
52 | #define LOG_INFO(fmt, ...) xop::Logger::instance().log2(LOG_INFO, fmt, ##__VA_ARGS__)
53 | #define LOG_ERROR(fmt, ...) xop::Logger::instance().log(LOG_ERROR, __FILE__, __FUNCTION__,__LINE__, fmt, ##__VA_ARGS__)
54 |
55 | #endif
56 |
57 |
--------------------------------------------------------------------------------
/src/net/MemoryManager.cpp:
--------------------------------------------------------------------------------
1 | #include "MemoryManager.h"
2 |
3 | using namespace xop;
4 |
5 | void* xop::Alloc(uint32_t size)
6 | {
7 | return MemoryManager::Instance().Alloc(size);
8 | }
9 |
10 | void xop::Free(void *ptr)
11 | {
12 | return MemoryManager::Instance().Free(ptr);
13 | }
14 |
15 | MemoryPool::MemoryPool()
16 | {
17 |
18 | }
19 |
20 | MemoryPool::~MemoryPool()
21 | {
22 | if (memory_) {
23 | free(memory_);
24 | }
25 | }
26 |
27 | void MemoryPool::Init(uint32_t size, uint32_t n)
28 | {
29 | if (memory_) {
30 | return;
31 | }
32 |
33 | block_size_ = size;
34 | num_blocks_ = n;
35 | memory_ = (char*)malloc(num_blocks_ * (block_size_ + sizeof(MemoryBlock)));
36 | head_ = (MemoryBlock*)memory_;
37 | head_->blockId = 1;
38 | head_->pool = this;
39 | head_->next = nullptr;
40 |
41 | MemoryBlock* current = head_;
42 | for (uint32_t n = 1; n < num_blocks_; n++) {
43 | MemoryBlock* next = (MemoryBlock*)(memory_ + (n * (block_size_ + sizeof(MemoryBlock))));
44 | next->blockId = n + 1;
45 | next->pool = this;
46 | next->next = nullptr;
47 |
48 | current->next = next;
49 | current = next;
50 | }
51 | }
52 |
53 | void* MemoryPool::Alloc(uint32_t size)
54 | {
55 | MemoryBlock* block = nullptr;
56 |
57 | std::lock_guard locker(mutex_);
58 | if (head_ != nullptr) {
59 | MemoryBlock* block = head_;
60 | head_ = head_->next;
61 | return ((char*)block + sizeof(MemoryBlock));
62 | }
63 |
64 | return nullptr;
65 | }
66 |
67 | void MemoryPool::Free(void* ptr)
68 | {
69 | MemoryBlock *block = (MemoryBlock*)((char*)ptr - sizeof(MemoryBlock));
70 | if (block->blockId != 0) {
71 | std::lock_guard locker(mutex_);
72 | block->next = head_;
73 | head_ = block;
74 | }
75 | }
76 |
77 | MemoryManager::MemoryManager()
78 | {
79 | memory_pools_[0].Init(4096, 50);
80 | memory_pools_[1].Init(40960, 10);
81 | memory_pools_[2].Init(102400, 5);
82 | //memory_pools_[3].Init(204800, 2);
83 | }
84 |
85 | MemoryManager::~MemoryManager()
86 | {
87 |
88 | }
89 |
90 | MemoryManager& MemoryManager::Instance()
91 | {
92 | static MemoryManager s_mgr;
93 | return s_mgr;
94 | }
95 |
96 | void* MemoryManager::Alloc(uint32_t size)
97 | {
98 | for (int n = 0; n < kMaxMemoryPool; n++) {
99 | if (size <= memory_pools_[n].BolckSize()) {
100 | void* ptr = memory_pools_[n].Alloc(size);
101 | if (ptr != nullptr) {
102 | return ptr;
103 | }
104 | else {
105 | break;
106 | }
107 | }
108 | }
109 |
110 | MemoryBlock *block = (MemoryBlock*)malloc(size + sizeof(MemoryBlock));
111 | block->blockId = 0;
112 | block->pool = nullptr;
113 | block->next = nullptr;
114 | return ((char*)block + sizeof(MemoryBlock));
115 | }
116 |
117 | void MemoryManager::Free(void* ptr)
118 | {
119 | MemoryBlock *block = (MemoryBlock*)((char*)ptr - sizeof(MemoryBlock));
120 | MemoryPool *pool = block->pool;
121 |
122 | if (pool != nullptr && block->blockId > 0) {
123 | pool->Free(ptr);
124 | }
125 | else {
126 | ::free(block);
127 | }
128 | }
--------------------------------------------------------------------------------
/src/net/MemoryManager.h:
--------------------------------------------------------------------------------
1 | #ifndef XOP_MEMMORY_MANAGER_H
2 | #define XOP_MEMMORY_MANAGER_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | namespace xop
10 | {
11 |
12 | void* Alloc(uint32_t size);
13 | void Free(void *ptr);
14 |
15 | class MemoryPool;
16 |
17 | struct MemoryBlock
18 | {
19 | uint32_t blockId = 0;
20 | MemoryPool *pool = nullptr;
21 | MemoryBlock *next = nullptr;
22 | };
23 |
24 | class MemoryPool
25 | {
26 | public:
27 | MemoryPool();
28 | ~MemoryPool();
29 |
30 | void Init(uint32_t size, uint32_t n);
31 | void* Alloc(uint32_t size);
32 | void Free(void* ptr);
33 |
34 | size_t BolckSize() const
35 | { return block_size_; }
36 |
37 | //private:
38 | char* memory_ = nullptr;
39 | uint32_t block_size_ = 0;
40 | uint32_t num_blocks_ = 0;
41 | MemoryBlock* head_ = nullptr;
42 | std::mutex mutex_;
43 | };
44 |
45 | class MemoryManager
46 | {
47 | public:
48 | static MemoryManager& Instance();
49 | ~MemoryManager();
50 |
51 | void* Alloc(uint32_t size);
52 | void Free(void* ptr);
53 |
54 | private:
55 | MemoryManager();
56 |
57 | static const int kMaxMemoryPool = 3;
58 | MemoryPool memory_pools_[kMaxMemoryPool];
59 | };
60 |
61 | }
62 | #endif
63 |
--------------------------------------------------------------------------------
/src/net/NetInterface.cpp:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #include "NetInterface.h"
5 | #include "Socket.h"
6 |
7 | using namespace xop;
8 |
9 | std::string NetInterface::GetLocalIPAddress()
10 | {
11 | #if defined(__linux) || defined(__linux__)
12 | SOCKET sockfd = 0;
13 | char buf[512] = { 0 };
14 | struct ifconf ifconf;
15 | struct ifreq *ifreq;
16 | sockfd = socket(AF_INET, SOCK_DGRAM, 0);
17 | if (sockfd == INVALID_SOCKET)
18 | {
19 | close(sockfd);
20 | return "0.0.0.0";
21 | }
22 |
23 | ifconf.ifc_len = 512;
24 | ifconf.ifc_buf = buf;
25 | if (ioctl(sockfd, SIOCGIFCONF, &ifconf) < 0)
26 | {
27 | close(sockfd);
28 | return "0.0.0.0";
29 | }
30 |
31 | close(sockfd);
32 |
33 | ifreq = (struct ifreq*)ifconf.ifc_buf;
34 | for (int i = (ifconf.ifc_len / sizeof(struct ifreq)); i>0; i--)
35 | {
36 | if (ifreq->ifr_flags == AF_INET)
37 | {
38 | if (strcmp(ifreq->ifr_name, "lo") != 0)
39 | {
40 | return inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr);
41 | }
42 | ifreq++;
43 | }
44 | }
45 | return "0.0.0.0";
46 | #elif defined(WIN32) || defined(_WIN32)
47 | PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO();
48 | unsigned long size = sizeof(IP_ADAPTER_INFO);
49 |
50 | int ret = GetAdaptersInfo(pIpAdapterInfo, &size);
51 | if (ret == ERROR_BUFFER_OVERFLOW)
52 | {
53 | delete pIpAdapterInfo;
54 | pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[size];
55 | ret = GetAdaptersInfo(pIpAdapterInfo, &size);
56 | }
57 |
58 | if (ret != ERROR_SUCCESS)
59 | {
60 | delete pIpAdapterInfo;
61 | return "0.0.0.0";
62 | }
63 |
64 | while (pIpAdapterInfo)
65 | {
66 | IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList);
67 | while(pIpAddrString)
68 | {
69 | if (strcmp(pIpAddrString->IpAddress.String, "127.0.0.1")!=0
70 | && strcmp(pIpAddrString->IpAddress.String, "0.0.0.0")!=0)
71 | {
72 | // pIpAddrString->IpMask.String
73 | //pIpAdapterInfo->GatewayList.IpAddress.String
74 | std::string ip(pIpAddrString->IpAddress.String);
75 | //delete pIpAdapterInfo;
76 | return ip;
77 | }
78 | pIpAddrString = pIpAddrString->Next;
79 | } while (pIpAddrString);
80 | pIpAdapterInfo = pIpAdapterInfo->Next;
81 | }
82 |
83 | delete pIpAdapterInfo;
84 | return "0.0.0.0";
85 | #else
86 | return "0.0.0.0";
87 | #endif
88 | }
89 |
90 |
91 |
--------------------------------------------------------------------------------
/src/net/NetInterface.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_NET_INTERFACE_H
5 | #define XOP_NET_INTERFACE_H
6 |
7 | #include
8 |
9 | namespace xop {
10 |
11 | class NetInterface
12 | {
13 | public:
14 | static std::string GetLocalIPAddress();
15 | };
16 |
17 | }
18 |
19 | #endif
20 |
--------------------------------------------------------------------------------
/src/net/Pipe.cpp:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #include "Pipe.h"
5 | #include "SocketUtil.h"
6 | #include
7 |
8 | using namespace xop;
9 |
10 | Pipe::Pipe()
11 | {
12 |
13 | }
14 |
15 | bool Pipe::Create()
16 | {
17 | #if defined(WIN32) || defined(_WIN32)
18 | TcpSocket rp(socket(AF_INET, SOCK_STREAM, 0)), wp(socket(AF_INET, SOCK_STREAM, 0));
19 | std::random_device rd;
20 |
21 | pipe_fd_[0] = rp.GetSocket();
22 | pipe_fd_[1] = wp.GetSocket();
23 | uint16_t port = 0;
24 | int again = 5;
25 |
26 | while(again--) {
27 | port = rd(); // random
28 | if (rp.Bind("127.0.0.1", port)) {
29 | break;
30 | }
31 | }
32 |
33 | if (again == 0) {
34 | return false;
35 | }
36 |
37 | if (!rp.Listen(1)) {
38 | return false;
39 | }
40 |
41 | if (!wp.Connect("127.0.0.1", port)) {
42 | return false;
43 | }
44 |
45 | if ((pipe_fd_[0] = rp.Accept()) < 0) {
46 | return false;
47 | }
48 |
49 | SocketUtil::SetNonBlock(pipe_fd_[0]);
50 | SocketUtil::SetNonBlock(pipe_fd_[1]);
51 | #elif defined(__linux) || defined(__linux__)
52 | if (pipe2(pipe_fd_, O_NONBLOCK | O_CLOEXEC) < 0) {
53 | return false;
54 | }
55 | #endif
56 | return true;
57 | }
58 |
59 | int Pipe::Write(void *buf, int len)
60 | {
61 | #if defined(WIN32) || defined(_WIN32)
62 | return ::send(pipe_fd_[1], (char *)buf, len, 0);
63 | #elif defined(__linux) || defined(__linux__)
64 | return ::write(pipe_fd_[1], buf, len);
65 | #endif
66 | }
67 |
68 | int Pipe::Read(void *buf, int len)
69 | {
70 | #if defined(WIN32) || defined(_WIN32)
71 | return recv(pipe_fd_[0], (char *)buf, len, 0);
72 | #elif defined(__linux) || defined(__linux__)
73 | return ::read(pipe_fd_[0], buf, len);
74 | #endif
75 | }
76 |
77 | void Pipe::Close()
78 | {
79 | #if defined(WIN32) || defined(_WIN32)
80 | closesocket(pipe_fd_[0]);
81 | closesocket(pipe_fd_[1]);
82 | #elif defined(__linux) || defined(__linux__)
83 | ::close(pipe_fd_[0]);
84 | ::close(pipe_fd_[1]);
85 | #endif
86 |
87 | }
88 |
89 |
90 |
--------------------------------------------------------------------------------
/src/net/Pipe.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_PIPE_H
5 | #define XOP_PIPE_H
6 |
7 | #include "TcpSocket.h"
8 |
9 | namespace xop
10 | {
11 |
12 | class Pipe
13 | {
14 | public:
15 | Pipe();
16 | bool Create();
17 | int Write(void *buf, int len);
18 | int Read(void *buf, int len);
19 | void Close();
20 |
21 | SOCKET Read() const { return pipe_fd_[0]; }
22 | SOCKET Write() const { return pipe_fd_[1]; }
23 |
24 | private:
25 | SOCKET pipe_fd_[2];
26 | };
27 |
28 | }
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/src/net/RingBuffer.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_RING_BUFFER_H
5 | #define XOP_RING_BUFFER_H
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | namespace xop
13 | {
14 |
15 | template
16 | class RingBuffer
17 | {
18 | public:
19 | RingBuffer(unsigned capacity=60)
20 | : _buffer(capacity)
21 | , _capacity(capacity)
22 | , _numDatas(0)
23 | { }
24 |
25 | ~RingBuffer() { }
26 |
27 | bool push(const T& data) { return pushData(std::forward(data)); }
28 | bool push(T&& data) { return pushData(data); }
29 |
30 | bool pop(T& data)
31 | {
32 | if(_numDatas > 0)
33 | {
34 | data = std::move(_buffer[_getPos]);
35 | add(_getPos);
36 | _numDatas--;
37 | return true;
38 | }
39 |
40 | return false;
41 | }
42 |
43 | bool isFull() const { return ((_numDatas==_capacity)?true:false); }
44 | bool isEmpty() const { return ((_numDatas==0)?true:false); }
45 | int size() const { return _numDatas; }
46 |
47 | private:
48 | template
49 | bool pushData(F&& data)
50 | {
51 | if (_numDatas < _capacity)
52 | {
53 | _buffer[_putPos] = std::forward(data);
54 | add(_putPos);
55 | _numDatas++;
56 | return true;
57 | }
58 |
59 | return false;
60 | }
61 |
62 | void add(int& pos)
63 | {
64 | pos = (((pos+1)==_capacity) ? 0 : (pos+1));
65 | }
66 |
67 | int _capacity = 0;
68 | int _putPos = 0;
69 | int _getPos = 0;
70 |
71 | std::atomic_int _numDatas;
72 | std::vector _buffer;
73 | };
74 |
75 | }
76 |
77 | #endif
78 |
79 |
80 |
--------------------------------------------------------------------------------
/src/net/SelectTaskScheduler.cpp:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #include "SelectTaskScheduler.h"
5 | #include "Logger.h"
6 | #include "Timer.h"
7 | #include
8 | #include
9 |
10 | using namespace xop;
11 |
12 | #define SELECT_CTL_ADD 0
13 | #define SELECT_CTL_MOD 1
14 | #define SELECT_CTL_DEL 2
15 |
16 | SelectTaskScheduler::SelectTaskScheduler(int id)
17 | : TaskScheduler(id)
18 | {
19 | FD_ZERO(&fd_read_backup_);
20 | FD_ZERO(&fd_write_backup_);
21 | FD_ZERO(&fd_exp_backup_);
22 |
23 | this->UpdateChannel(wakeup_channel_);
24 | }
25 |
26 | SelectTaskScheduler::~SelectTaskScheduler()
27 | {
28 |
29 | }
30 |
31 | void SelectTaskScheduler::UpdateChannel(ChannelPtr channel)
32 | {
33 | std::lock_guard lock(mutex_);
34 |
35 | SOCKET socket = channel->GetSocket();
36 |
37 | if(channels_.find(socket) != channels_.end()) {
38 | if(channel->IsNoneEvent()) {
39 | is_fd_read_reset_ = true;
40 | is_fd_write_reset_ = true;
41 | is_fd_exp_reset_ = true;
42 | channels_.erase(socket);
43 | }
44 | else {
45 | //is_fd_read_reset_ = true;
46 | is_fd_write_reset_ = true;
47 | }
48 | }
49 | else {
50 | if(!channel->IsNoneEvent()) {
51 | channels_.emplace(socket, channel);
52 | is_fd_read_reset_ = true;
53 | is_fd_write_reset_ = true;
54 | is_fd_exp_reset_ = true;
55 | }
56 | }
57 | }
58 |
59 | void SelectTaskScheduler::RemoveChannel(ChannelPtr& channel)
60 | {
61 | std::lock_guard lock(mutex_);
62 |
63 | SOCKET fd = channel->GetSocket();
64 |
65 | if(channels_.find(fd) != channels_.end()) {
66 | is_fd_read_reset_ = true;
67 | is_fd_write_reset_ = true;
68 | is_fd_exp_reset_ = true;
69 | channels_.erase(fd);
70 | }
71 | }
72 |
73 | bool SelectTaskScheduler::HandleEvent(int timeout)
74 | {
75 | if(channels_.empty()) {
76 | if (timeout <= 0) {
77 | timeout = 10;
78 | }
79 |
80 | Timer::Sleep(timeout);
81 | return true;
82 | }
83 |
84 | fd_set fd_read;
85 | fd_set fd_write;
86 | fd_set fd_exp;
87 | FD_ZERO(&fd_read);
88 | FD_ZERO(&fd_write);
89 | FD_ZERO(&fd_exp);
90 | bool fd_read_reset = false;
91 | bool fd_write_reset = false;
92 | bool fd_exp_reset = false;
93 |
94 | if(is_fd_read_reset_ || is_fd_write_reset_ || is_fd_exp_reset_) {
95 | if (is_fd_exp_reset_) {
96 | maxfd_ = 0;
97 | }
98 |
99 | std::lock_guard lock(mutex_);
100 | for(auto iter : channels_) {
101 | int events = iter.second->GetEvents();
102 | SOCKET fd = iter.second->GetSocket();
103 |
104 | if (is_fd_read_reset_ && (events&EVENT_IN)) {
105 | FD_SET(fd, &fd_read);
106 | }
107 |
108 | if(is_fd_write_reset_ && (events&EVENT_OUT)) {
109 | FD_SET(fd, &fd_write);
110 | }
111 |
112 | if(is_fd_exp_reset_) {
113 | FD_SET(fd, &fd_exp);
114 | if(fd > maxfd_) {
115 | maxfd_ = fd;
116 | }
117 | }
118 | }
119 |
120 | fd_read_reset = is_fd_read_reset_;
121 | fd_write_reset = is_fd_write_reset_;
122 | fd_exp_reset = is_fd_exp_reset_;
123 | is_fd_read_reset_ = false;
124 | is_fd_write_reset_ = false;
125 | is_fd_exp_reset_ = false;
126 | }
127 |
128 | if(fd_read_reset) {
129 | FD_ZERO(&fd_read_backup_);
130 | memcpy(&fd_read_backup_, &fd_read, sizeof(fd_set));
131 | }
132 | else {
133 | memcpy(&fd_read, &fd_read_backup_, sizeof(fd_set));
134 | }
135 |
136 |
137 | if(fd_write_reset) {
138 | FD_ZERO(&fd_write_backup_);
139 | memcpy(&fd_write_backup_, &fd_write, sizeof(fd_set));
140 | }
141 | else {
142 | memcpy(&fd_write, &fd_write_backup_, sizeof(fd_set));
143 | }
144 |
145 |
146 | if(fd_exp_reset) {
147 | FD_ZERO(&fd_exp_backup_);
148 | memcpy(&fd_exp_backup_, &fd_exp, sizeof(fd_set));
149 | }
150 | else {
151 | memcpy(&fd_exp, &fd_exp_backup_, sizeof(fd_set));
152 | }
153 |
154 | if(timeout <= 0) {
155 | timeout = 10;
156 | }
157 |
158 | struct timeval tv = { timeout/1000, timeout%1000*1000 };
159 | int ret = select((int)maxfd_+1, &fd_read, &fd_write, &fd_exp, &tv);
160 | if (ret < 0) {
161 | #if defined(__linux) || defined(__linux__)
162 | if(errno == EINTR) {
163 | return true;
164 | }
165 | #endif
166 | return false;
167 | }
168 |
169 | std::forward_list> event_list;
170 | if(ret > 0) {
171 | std::lock_guard lock(mutex_);
172 | for(auto iter : channels_) {
173 | int events = 0;
174 | SOCKET socket = iter.second->GetSocket();
175 |
176 | if (FD_ISSET(socket, &fd_read)) {
177 | events |= EVENT_IN;
178 | }
179 |
180 | if (FD_ISSET(socket, &fd_write)) {
181 | events |= EVENT_OUT;
182 | }
183 |
184 | if (FD_ISSET(socket, &fd_exp)) {
185 | events |= (EVENT_HUP); // close
186 | }
187 |
188 | if(events != 0) {
189 | event_list.emplace_front(iter.second, events);
190 | }
191 | }
192 | }
193 |
194 | for(auto& iter: event_list) {
195 | iter.first->HandleEvent(iter.second);
196 | }
197 |
198 | return true;
199 | }
200 |
201 |
202 |
203 |
--------------------------------------------------------------------------------
/src/net/SelectTaskScheduler.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_SELECT_TASK_SCHEDULER_H
5 | #define XOP_SELECT_TASK_SCHEDULER_H
6 |
7 | #include "TaskScheduler.h"
8 | #include "Socket.h"
9 | #include
10 | #include
11 |
12 | #if defined(__linux) || defined(__linux__)
13 | #include
14 | #include
15 | #include
16 | #include
17 | #endif
18 |
19 | namespace xop
20 | {
21 |
22 | class SelectTaskScheduler : public TaskScheduler
23 | {
24 | public:
25 | SelectTaskScheduler(int id = 0);
26 | virtual ~SelectTaskScheduler();
27 |
28 | void UpdateChannel(ChannelPtr channel);
29 | void RemoveChannel(ChannelPtr& channel);
30 | bool HandleEvent(int timeout);
31 |
32 | private:
33 | fd_set fd_read_backup_;
34 | fd_set fd_write_backup_;
35 | fd_set fd_exp_backup_;
36 | SOCKET maxfd_ = 0;
37 |
38 | bool is_fd_read_reset_ = false;
39 | bool is_fd_write_reset_ = false;
40 | bool is_fd_exp_reset_ = false;
41 |
42 | std::mutex mutex_;
43 | std::unordered_map channels_;
44 | };
45 |
46 | }
47 |
48 | #endif
49 |
--------------------------------------------------------------------------------
/src/net/Socket.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_SOCKET_H
5 | #define XOP_SOCKET_H
6 |
7 | #if defined(__linux) || defined(__linux__)
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #define SOCKET int
25 | #define INVALID_SOCKET (-1)
26 | #define SOCKET_ERROR (-1)
27 |
28 | #elif defined(WIN32) || defined(_WIN32)
29 | #define FD_SETSIZE 1024
30 | #define WIN32_LEAN_AND_MEAN
31 | #define _WINSOCK_DEPRECATED_NO_WARNINGS
32 | #include
33 | #include
34 | #include
35 | #include
36 | #define SHUT_RD 0
37 | #define SHUT_WR 1
38 | #define SHUT_RDWR 2
39 |
40 | #else
41 |
42 | #endif
43 |
44 | #include
45 | #include
46 |
47 | #endif // _XOP_SOCKET_H
48 |
--------------------------------------------------------------------------------
/src/net/SocketUtil.cpp:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #include "SocketUtil.h"
5 | #include "Socket.h"
6 | #include
7 |
8 | using namespace xop;
9 |
10 | bool SocketUtil::Bind(SOCKET sockfd, std::string ip, uint16_t port)
11 | {
12 | struct sockaddr_in addr = {0};
13 | addr.sin_family = AF_INET;
14 | addr.sin_addr.s_addr = inet_addr(ip.c_str());
15 | addr.sin_port = htons(port);
16 |
17 | if(::bind(sockfd, (struct sockaddr*)&addr, sizeof addr) == SOCKET_ERROR) {
18 | return false;
19 | }
20 |
21 | return true;
22 | }
23 |
24 | void SocketUtil::SetNonBlock(SOCKET fd)
25 | {
26 | #if defined(__linux) || defined(__linux__)
27 | int flags = fcntl(fd, F_GETFL, 0);
28 | fcntl(fd, F_SETFL, flags | O_NONBLOCK);
29 | #else
30 | unsigned long on = 1;
31 | ioctlsocket(fd, FIONBIO, &on);
32 | #endif
33 | }
34 |
35 | void SocketUtil::SetBlock(SOCKET fd, int writeTimeout)
36 | {
37 | #if defined(__linux) || defined(__linux__)
38 | int flags = fcntl(fd, F_GETFL, 0);
39 | fcntl(fd, F_SETFL, flags&(~O_NONBLOCK));
40 | #elif defined(WIN32) || defined(_WIN32)
41 | unsigned long on = 0;
42 | ioctlsocket(fd, FIONBIO, &on);
43 | #else
44 | #endif
45 | if(writeTimeout > 0)
46 | {
47 | #ifdef SO_SNDTIMEO
48 | #if defined(__linux) || defined(__linux__)
49 | struct timeval tv = {writeTimeout/1000, (writeTimeout%1000)*1000};
50 | setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof tv);
51 | #elif defined(WIN32) || defined(_WIN32)
52 | unsigned long ms = (unsigned long)writeTimeout;
53 | setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&ms, sizeof(unsigned long));
54 | #else
55 | #endif
56 | #endif
57 | }
58 | }
59 |
60 | void SocketUtil::SetReuseAddr(SOCKET sockfd)
61 | {
62 | int on = 1;
63 | setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof on);
64 | }
65 |
66 | void SocketUtil::SetReusePort(SOCKET sockfd)
67 | {
68 | #ifdef SO_REUSEPORT
69 | int on = 1;
70 | setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&on, sizeof(on));
71 | #endif
72 | }
73 |
74 | void SocketUtil::SetNoDelay(SOCKET sockfd)
75 | {
76 | #ifdef TCP_NODELAY
77 | int on = 1;
78 | int ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&on, sizeof(on));
79 | #endif
80 | }
81 |
82 | void SocketUtil::SetKeepAlive(SOCKET sockfd)
83 | {
84 | int on = 1;
85 | setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on));
86 | }
87 |
88 | void SocketUtil::SetNoSigpipe(SOCKET sockfd)
89 | {
90 | #ifdef SO_NOSIGPIPE
91 | int on = 1;
92 | setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (char *)&on, sizeof(on));
93 | #endif
94 | }
95 |
96 | void SocketUtil::SetSendBufSize(SOCKET sockfd, int size)
97 | {
98 | setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size));
99 | }
100 |
101 | void SocketUtil::SetRecvBufSize(SOCKET sockfd, int size)
102 | {
103 | setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size));
104 | }
105 |
106 | std::string SocketUtil::GetPeerIp(SOCKET sockfd)
107 | {
108 | struct sockaddr_in addr = { 0 };
109 | socklen_t addrlen = sizeof(struct sockaddr_in);
110 | if (getpeername(sockfd, (struct sockaddr *)&addr, &addrlen) == 0)
111 | {
112 | return inet_ntoa(addr.sin_addr);
113 | }
114 |
115 | return "0.0.0.0";
116 | }
117 |
118 | uint16_t SocketUtil::GetPeerPort(SOCKET sockfd)
119 | {
120 | struct sockaddr_in addr = { 0 };
121 | socklen_t addrlen = sizeof(struct sockaddr_in);
122 | if (getpeername(sockfd, (struct sockaddr *)&addr, &addrlen) == 0)
123 | {
124 | return ntohs(addr.sin_port);
125 | }
126 |
127 | return 0;
128 | }
129 |
130 | int SocketUtil::GetPeerAddr(SOCKET sockfd, struct sockaddr_in *addr)
131 | {
132 | socklen_t addrlen = sizeof(struct sockaddr_in);
133 | return getpeername(sockfd, (struct sockaddr *)addr, &addrlen);
134 | }
135 |
136 | void SocketUtil::Close(SOCKET sockfd)
137 | {
138 | #if defined(__linux) || defined(__linux__)
139 | ::close(sockfd);
140 | #elif defined(WIN32) || defined(_WIN32)
141 | ::closesocket(sockfd);
142 | #endif
143 | }
144 |
145 | bool SocketUtil::Connect(SOCKET sockfd, std::string ip, uint16_t port, int timeout)
146 | {
147 | bool isConnected = true;
148 | if (timeout > 0)
149 | {
150 | SocketUtil::SetNonBlock(sockfd);
151 | }
152 |
153 | struct sockaddr_in addr = { 0 };
154 | socklen_t addrlen = sizeof(addr);
155 | addr.sin_family = AF_INET;
156 | addr.sin_port = htons(port);
157 | addr.sin_addr.s_addr = inet_addr(ip.c_str());
158 | if (::connect(sockfd, (struct sockaddr*)&addr, addrlen) == SOCKET_ERROR)
159 | {
160 | if (timeout > 0)
161 | {
162 | isConnected = false;
163 | fd_set fdWrite;
164 | FD_ZERO(&fdWrite);
165 | FD_SET(sockfd, &fdWrite);
166 | struct timeval tv = { timeout / 1000, timeout % 1000 * 1000 };
167 | select((int)sockfd + 1, NULL, &fdWrite, NULL, &tv);
168 | if (FD_ISSET(sockfd, &fdWrite))
169 | {
170 | isConnected = true;
171 | }
172 | SocketUtil::SetBlock(sockfd);
173 | }
174 | else
175 | {
176 | isConnected = false;
177 | }
178 | }
179 |
180 | return isConnected;
181 | }
182 |
183 |
--------------------------------------------------------------------------------
/src/net/SocketUtil.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_SOCKET_UTIL_H
5 | #define XOP_SOCKET_UTIL_H
6 |
7 | #include "Socket.h"
8 | #include
9 |
10 | namespace xop
11 | {
12 |
13 | class SocketUtil
14 | {
15 | public:
16 | static bool Bind(SOCKET sockfd, std::string ip, uint16_t port);
17 | static void SetNonBlock(SOCKET fd);
18 | static void SetBlock(SOCKET fd, int write_timeout=0);
19 | static void SetReuseAddr(SOCKET fd);
20 | static void SetReusePort(SOCKET sockfd);
21 | static void SetNoDelay(SOCKET sockfd);
22 | static void SetKeepAlive(SOCKET sockfd);
23 | static void SetNoSigpipe(SOCKET sockfd);
24 | static void SetSendBufSize(SOCKET sockfd, int size);
25 | static void SetRecvBufSize(SOCKET sockfd, int size);
26 | static std::string GetPeerIp(SOCKET sockfd);
27 | static uint16_t GetPeerPort(SOCKET sockfd);
28 | static int GetPeerAddr(SOCKET sockfd, struct sockaddr_in *addr);
29 | static void Close(SOCKET sockfd);
30 | static bool Connect(SOCKET sockfd, std::string ip, uint16_t port, int timeout=0);
31 | };
32 |
33 | }
34 |
35 | #endif // _SOCKET_UTIL_H
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/net/TaskScheduler.cpp:
--------------------------------------------------------------------------------
1 | #include "TaskScheduler.h"
2 | #if defined(__linux) || defined(__linux__)
3 | #include
4 | #endif
5 |
6 | using namespace xop;
7 |
8 | TaskScheduler::TaskScheduler(int id)
9 | : id_(id)
10 | , is_shutdown_(false)
11 | , wakeup_pipe_(new Pipe())
12 | , trigger_events_(new xop::RingBuffer(kMaxTriggetEvents))
13 | {
14 | static std::once_flag flag;
15 | std::call_once(flag, [] {
16 | #if defined(WIN32) || defined(_WIN32)
17 | WSADATA wsa_data;
18 | if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) {
19 | WSACleanup();
20 | }
21 | #endif
22 | });
23 |
24 | if (wakeup_pipe_->Create()) {
25 | wakeup_channel_.reset(new Channel(wakeup_pipe_->Read()));
26 | wakeup_channel_->EnableReading();
27 | wakeup_channel_->SetReadCallback([this]() { this->Wake(); });
28 | }
29 | }
30 |
31 | TaskScheduler::~TaskScheduler()
32 | {
33 |
34 | }
35 |
36 | void TaskScheduler::Start()
37 | {
38 | #if defined(__linux) || defined(__linux__)
39 | signal(SIGPIPE, SIG_IGN);
40 | signal(SIGQUIT, SIG_IGN);
41 | signal(SIGUSR1, SIG_IGN);
42 | signal(SIGTERM, SIG_IGN);
43 | signal(SIGKILL, SIG_IGN);
44 | #endif
45 | is_shutdown_ = false;
46 | while (!is_shutdown_) {
47 | this->HandleTriggerEvent();
48 | this->timer_queue_.HandleTimerEvent();
49 | int64_t timeout = this->timer_queue_.GetTimeRemaining();
50 | this->HandleEvent((int)timeout);
51 | }
52 | }
53 |
54 | void TaskScheduler::Stop()
55 | {
56 | is_shutdown_ = true;
57 | char event = kTriggetEvent;
58 | wakeup_pipe_->Write(&event, 1);
59 | }
60 |
61 | TimerId TaskScheduler::AddTimer(TimerEvent timerEvent, uint32_t msec)
62 | {
63 | TimerId id = timer_queue_.AddTimer(timerEvent, msec);
64 | return id;
65 | }
66 |
67 | void TaskScheduler::RemoveTimer(TimerId timerId)
68 | {
69 | timer_queue_.RemoveTimer(timerId);
70 | }
71 |
72 | bool TaskScheduler::AddTriggerEvent(TriggerEvent callback)
73 | {
74 | if (trigger_events_->size() < kMaxTriggetEvents) {
75 | std::lock_guard lock(mutex_);
76 | char event = kTriggetEvent;
77 | trigger_events_->push(std::move(callback));
78 | wakeup_pipe_->Write(&event, 1);
79 | return true;
80 | }
81 |
82 | return false;
83 | }
84 |
85 | void TaskScheduler::Wake()
86 | {
87 | char event[10] = { 0 };
88 | while (wakeup_pipe_->Read(event, 10) > 0);
89 | }
90 |
91 | void TaskScheduler::HandleTriggerEvent()
92 | {
93 | do
94 | {
95 | TriggerEvent callback;
96 | if (trigger_events_->pop(callback)) {
97 | callback();
98 | }
99 | } while (trigger_events_->size() > 0);
100 | }
--------------------------------------------------------------------------------
/src/net/TaskScheduler.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_TASK_SCHEDULER_H
5 | #define XOP_TASK_SCHEDULER_H
6 |
7 | #include "Channel.h"
8 | #include "Pipe.h"
9 | #include "Timer.h"
10 | #include "RingBuffer.h"
11 |
12 | namespace xop
13 | {
14 |
15 | typedef std::function TriggerEvent;
16 |
17 | class TaskScheduler
18 | {
19 | public:
20 | TaskScheduler(int id=1);
21 | virtual ~TaskScheduler();
22 |
23 | void Start();
24 | void Stop();
25 | TimerId AddTimer(TimerEvent timerEvent, uint32_t msec);
26 | void RemoveTimer(TimerId timerId);
27 | bool AddTriggerEvent(TriggerEvent callback);
28 |
29 | virtual void UpdateChannel(ChannelPtr channel) { };
30 | virtual void RemoveChannel(ChannelPtr& channel) { };
31 | virtual bool HandleEvent(int timeout) { return false; };
32 |
33 | int GetId() const
34 | { return id_; }
35 |
36 | protected:
37 | void Wake();
38 | void HandleTriggerEvent();
39 |
40 | int id_ = 0;
41 | std::atomic_bool is_shutdown_;
42 | std::unique_ptr wakeup_pipe_;
43 | std::shared_ptr wakeup_channel_;
44 | std::unique_ptr> trigger_events_;
45 |
46 | std::mutex mutex_;
47 | TimerQueue timer_queue_;
48 |
49 | static const char kTriggetEvent = 1;
50 | static const char kTimerEvent = 2;
51 | static const int kMaxTriggetEvents = 50000;
52 | };
53 |
54 | }
55 | #endif
56 |
57 |
--------------------------------------------------------------------------------
/src/net/TcpConnection.cpp:
--------------------------------------------------------------------------------
1 | #include "TcpConnection.h"
2 | #include "SocketUtil.h"
3 |
4 | using namespace xop;
5 |
6 | TcpConnection::TcpConnection(TaskScheduler *task_scheduler, SOCKET sockfd)
7 | : task_scheduler_(task_scheduler)
8 | , read_buffer_(new BufferReader)
9 | , write_buffer_(new BufferWriter(500))
10 | , channel_(new Channel(sockfd))
11 | {
12 | is_closed_ = false;
13 |
14 | channel_->SetReadCallback([this]() { this->HandleRead(); });
15 | channel_->SetWriteCallback([this]() { this->HandleWrite(); });
16 | channel_->SetCloseCallback([this]() { this->HandleClose(); });
17 | channel_->SetErrorCallback([this]() { this->HandleError(); });
18 |
19 | SocketUtil::SetNonBlock(sockfd);
20 | SocketUtil::SetSendBufSize(sockfd, 100 * 1024);
21 | SocketUtil::SetKeepAlive(sockfd);
22 |
23 | channel_->EnableReading();
24 | task_scheduler_->UpdateChannel(channel_);
25 | }
26 |
27 | TcpConnection::~TcpConnection()
28 | {
29 | SOCKET fd = channel_->GetSocket();
30 | if (fd > 0) {
31 | SocketUtil::Close(fd);
32 | }
33 | }
34 |
35 | void TcpConnection::Send(std::shared_ptr data, uint32_t size)
36 | {
37 | if (!is_closed_) {
38 | mutex_.lock();
39 | write_buffer_->Append(data, size);
40 | mutex_.unlock();
41 |
42 | this->HandleWrite();
43 | }
44 | }
45 |
46 | void TcpConnection::Send(const char *data, uint32_t size)
47 | {
48 | if (!is_closed_) {
49 | mutex_.lock();
50 | write_buffer_->Append(data, size);
51 | mutex_.unlock();
52 |
53 | this->HandleWrite();
54 | }
55 | }
56 |
57 | void TcpConnection::Disconnect()
58 | {
59 | std::lock_guard lock(mutex_);
60 | auto conn = shared_from_this();
61 | task_scheduler_->AddTriggerEvent([conn]() {
62 | conn->Close();
63 | });
64 | }
65 |
66 | void TcpConnection::HandleRead()
67 | {
68 | {
69 | std::lock_guard lock(mutex_);
70 |
71 | if (is_closed_) {
72 | return;
73 | }
74 |
75 | int ret = read_buffer_->Read(channel_->GetSocket());
76 | if (ret <= 0) {
77 | this->Close();
78 | return;
79 | }
80 | }
81 |
82 | if (read_cb_) {
83 | bool ret = read_cb_(shared_from_this(), *read_buffer_);
84 | if (false == ret) {
85 | std::lock_guard lock(mutex_);
86 | this->Close();
87 | }
88 | }
89 | }
90 |
91 | void TcpConnection::HandleWrite()
92 | {
93 | if (is_closed_) {
94 | return;
95 | }
96 |
97 | //std::lock_guard lock(mutex_);
98 | if (!mutex_.try_lock()) {
99 | return;
100 | }
101 |
102 | int ret = 0;
103 | bool empty = false;
104 | do
105 | {
106 | ret = write_buffer_->Send(channel_->GetSocket());
107 | if (ret < 0) {
108 | this->Close();
109 | mutex_.unlock();
110 | return;
111 | }
112 | empty = write_buffer_->IsEmpty();
113 | } while (0);
114 |
115 | if (empty) {
116 | if (channel_->IsWriting()) {
117 | channel_->DisableWriting();
118 | task_scheduler_->UpdateChannel(channel_);
119 | }
120 | }
121 | else if(!channel_->IsWriting()) {
122 | channel_->EnableWriting();
123 | task_scheduler_->UpdateChannel(channel_);
124 | }
125 |
126 | mutex_.unlock();
127 | }
128 |
129 | void TcpConnection::Close()
130 | {
131 | if (!is_closed_) {
132 | is_closed_ = true;
133 | task_scheduler_->RemoveChannel(channel_);
134 |
135 | if (close_cb_) {
136 | close_cb_(shared_from_this());
137 | }
138 |
139 | if (disconnect_cb_) {
140 | disconnect_cb_(shared_from_this());
141 | }
142 | }
143 | }
144 |
145 | void TcpConnection::HandleClose()
146 | {
147 | std::lock_guard lock(mutex_);
148 | this->Close();
149 | }
150 |
151 | void TcpConnection::HandleError()
152 | {
153 | std::lock_guard lock(mutex_);
154 | this->Close();
155 | }
156 |
--------------------------------------------------------------------------------
/src/net/TcpConnection.h:
--------------------------------------------------------------------------------
1 | #ifndef XOP_TCP_CONNECTION_H
2 | #define XOP_TCP_CONNECTION_H
3 |
4 | #include
5 | #include
6 | #include "TaskScheduler.h"
7 | #include "BufferReader.h"
8 | #include "BufferWriter.h"
9 | #include "Channel.h"
10 |
11 | namespace xop
12 | {
13 |
14 | class TcpConnection : public std::enable_shared_from_this
15 | {
16 | public:
17 | using Ptr = std::shared_ptr;
18 | using DisconnectCallback = std::function conn)> ;
19 | using CloseCallback = std::function conn)>;
20 | using ReadCallback = std::function conn, xop::BufferReader& buffer)>;
21 |
22 | TcpConnection(TaskScheduler *task_scheduler, SOCKET sockfd);
23 | virtual ~TcpConnection();
24 |
25 | TaskScheduler* GetTaskScheduler() const
26 | { return task_scheduler_; }
27 |
28 | void SetReadCallback(const ReadCallback& cb)
29 | { read_cb_ = cb; }
30 |
31 | void SetCloseCallback(const CloseCallback& cb)
32 | { close_cb_ = cb; }
33 |
34 | void Send(std::shared_ptr data, uint32_t size);
35 | void Send(const char *data, uint32_t size);
36 |
37 | void Disconnect();
38 |
39 | bool IsClosed() const
40 | { return is_closed_; }
41 |
42 | SOCKET GetSocket() const
43 | { return channel_->GetSocket(); }
44 |
45 | protected:
46 | friend class TcpServer;
47 |
48 | virtual void HandleRead();
49 | virtual void HandleWrite();
50 | virtual void HandleClose();
51 | virtual void HandleError();
52 |
53 | void SetDisconnectCallback(const DisconnectCallback& cb)
54 | { disconnect_cb_ = cb; }
55 |
56 | TaskScheduler* task_scheduler_;
57 | std::unique_ptr read_buffer_;
58 | std::unique_ptr write_buffer_;
59 | std::atomic_bool is_closed_;
60 |
61 | private:
62 | void Close();
63 |
64 | std::shared_ptr channel_;
65 | std::mutex mutex_;
66 | DisconnectCallback disconnect_cb_;
67 | CloseCallback close_cb_;
68 | ReadCallback read_cb_;
69 | };
70 |
71 | }
72 |
73 | #endif
74 |
--------------------------------------------------------------------------------
/src/net/TcpServer.cpp:
--------------------------------------------------------------------------------
1 | #include "TcpServer.h"
2 | #include "Acceptor.h"
3 | #include "EventLoop.h"
4 | #include "Logger.h"
5 | #include
6 |
7 | using namespace xop;
8 | using namespace std;
9 |
10 | TcpServer::TcpServer(EventLoop* event_loop)
11 | : event_loop_(event_loop)
12 | , port_(0)
13 | , acceptor_(new Acceptor(event_loop_))
14 | , is_started_(false)
15 | {
16 | acceptor_->SetNewConnectionCallback([this](SOCKET sockfd) {
17 | TcpConnection::Ptr conn = this->OnConnect(sockfd);
18 | if (conn) {
19 | this->AddConnection(sockfd, conn);
20 | conn->SetDisconnectCallback([this](TcpConnection::Ptr conn) {
21 | auto scheduler = conn->GetTaskScheduler();
22 | SOCKET sockfd = conn->GetSocket();
23 | if (!scheduler->AddTriggerEvent([this, sockfd] {this->RemoveConnection(sockfd); })) {
24 | scheduler->AddTimer([this, sockfd]() {this->RemoveConnection(sockfd); return false; }, 100);
25 | }
26 | });
27 | }
28 | });
29 | }
30 |
31 | TcpServer::~TcpServer()
32 | {
33 | Stop();
34 | }
35 |
36 | bool TcpServer::Start(std::string ip, uint16_t port)
37 | {
38 | Stop();
39 |
40 | if (!is_started_) {
41 | if (acceptor_->Listen(ip, port) < 0) {
42 | return false;
43 | }
44 |
45 | port_ = port;
46 | ip_ = ip;
47 | is_started_ = true;
48 | return true;
49 | }
50 |
51 | return false;
52 | }
53 |
54 | void TcpServer::Stop()
55 | {
56 | if (is_started_) {
57 |
58 | mutex_.lock();
59 | for (auto iter : connections_) {
60 | iter.second->Disconnect();
61 | }
62 | mutex_.unlock();
63 |
64 | acceptor_->Close();
65 | is_started_ = false;
66 |
67 | while (1) {
68 | Timer::Sleep(1);
69 | if (connections_.empty()) {
70 | break;
71 | }
72 | }
73 | }
74 | }
75 |
76 | TcpConnection::Ptr TcpServer::OnConnect(SOCKET sockfd)
77 | {
78 | return std::make_shared(event_loop_->GetTaskScheduler().get(), sockfd);
79 | }
80 |
81 | void TcpServer::AddConnection(SOCKET sockfd, TcpConnection::Ptr tcpConn)
82 | {
83 | std::lock_guard locker(mutex_);
84 | connections_.emplace(sockfd, tcpConn);
85 | }
86 |
87 | void TcpServer::RemoveConnection(SOCKET sockfd)
88 | {
89 | std::lock_guard locker(mutex_);
90 | connections_.erase(sockfd);
91 | }
92 |
--------------------------------------------------------------------------------
/src/net/TcpServer.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-11-10
3 |
4 | #ifndef XOP_TCPSERVER_H
5 | #define XOP_TCPSERVER_H
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "Socket.h"
12 | #include "TcpConnection.h"
13 |
14 | namespace xop
15 | {
16 |
17 | class Acceptor;
18 | class EventLoop;
19 |
20 | class TcpServer
21 | {
22 | public:
23 | TcpServer(EventLoop* event_loop);
24 | virtual ~TcpServer();
25 |
26 | virtual bool Start(std::string ip, uint16_t port);
27 | virtual void Stop();
28 |
29 | std::string GetIPAddress() const
30 | { return ip_; }
31 |
32 | uint16_t GetPort() const
33 | { return port_; }
34 |
35 | protected:
36 | virtual TcpConnection::Ptr OnConnect(SOCKET sockfd);
37 | virtual void AddConnection(SOCKET sockfd, TcpConnection::Ptr tcpConn);
38 | virtual void RemoveConnection(SOCKET sockfd);
39 |
40 | EventLoop* event_loop_;
41 | uint16_t port_;
42 | std::string ip_;
43 | std::unique_ptr acceptor_;
44 | bool is_started_;
45 | std::mutex mutex_;
46 | std::unordered_map> connections_;
47 | };
48 |
49 | }
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/src/net/TcpSocket.cpp:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #include "TcpSocket.h"
5 | #include "Socket.h"
6 | #include "SocketUtil.h"
7 | #include "Logger.h"
8 |
9 | using namespace xop;
10 |
11 | TcpSocket::TcpSocket(SOCKET sockfd)
12 | : sockfd_(sockfd)
13 | {
14 |
15 | }
16 |
17 | TcpSocket::~TcpSocket()
18 | {
19 |
20 | }
21 |
22 | SOCKET TcpSocket::Create()
23 | {
24 | sockfd_ = ::socket(AF_INET, SOCK_STREAM, 0);
25 | return sockfd_;
26 | }
27 |
28 | bool TcpSocket::Bind(std::string ip, uint16_t port)
29 | {
30 | struct sockaddr_in addr = {0};
31 | addr.sin_family = AF_INET;
32 | addr.sin_addr.s_addr = inet_addr(ip.c_str());
33 | addr.sin_port = htons(port);
34 |
35 | if(::bind(sockfd_, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
36 | {
37 | LOG_DEBUG(" bind <%s:%u> failed.\n", sockfd_, ip.c_str(), port);
38 | return false;
39 | }
40 |
41 | return true;
42 | }
43 |
44 | bool TcpSocket::Listen(int backlog)
45 | {
46 | if(::listen(sockfd_, backlog) == SOCKET_ERROR)
47 | {
48 | LOG_DEBUG(" listen failed.\n", sockfd_);
49 | return false;
50 | }
51 |
52 | return true;
53 | }
54 |
55 | SOCKET TcpSocket::Accept()
56 | {
57 | struct sockaddr_in addr = {0};
58 | socklen_t addrlen = sizeof addr;
59 |
60 | SOCKET clientfd = ::accept(sockfd_, (struct sockaddr*)&addr, &addrlen);
61 |
62 | return clientfd;
63 | }
64 |
65 | bool TcpSocket::Connect(std::string ip, uint16_t port, int timeout)
66 | {
67 | if(!SocketUtil::Connect(sockfd_, ip, port, timeout))
68 | {
69 | LOG_DEBUG(" connect failed.\n", sockfd_);
70 | return false;
71 | }
72 |
73 | return true;
74 | }
75 |
76 | void TcpSocket::Close()
77 | {
78 | #if defined(__linux) || defined(__linux__)
79 | ::close(sockfd_);
80 | #elif defined(WIN32) || defined(_WIN32)
81 | closesocket(sockfd_);
82 | #else
83 |
84 | #endif
85 | sockfd_ = 0;
86 | }
87 |
88 | void TcpSocket::ShutdownWrite()
89 | {
90 | shutdown(sockfd_, SHUT_WR);
91 | sockfd_ = 0;
92 | }
93 |
--------------------------------------------------------------------------------
/src/net/TcpSocket.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef XOP_TCP_SOCKET_H
5 | #define XOP_TCP_SOCKET_H
6 |
7 | #include
8 | #include
9 | #include "Socket.h"
10 |
11 | namespace xop
12 | {
13 |
14 | class TcpSocket
15 | {
16 | public:
17 | TcpSocket(SOCKET sockfd=-1);
18 | virtual ~TcpSocket();
19 |
20 | SOCKET Create();
21 | bool Bind(std::string ip, uint16_t port);
22 | bool Listen(int backlog);
23 | SOCKET Accept();
24 | bool Connect(std::string ip, uint16_t port, int timeout = 0);
25 | void Close();
26 | void ShutdownWrite();
27 |
28 | SOCKET GetSocket() const { return sockfd_; }
29 |
30 | private:
31 | SOCKET sockfd_ = -1;
32 | };
33 |
34 | }
35 |
36 | #endif
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/net/ThreadSafeQueue.h:
--------------------------------------------------------------------------------
1 | #ifndef THREAD_SAFE_QUEUE_H
2 | #define THREAD_SAFE_QUEUE_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | namespace xop
9 | {
10 |
11 | template
12 | class ThreadSafeQueue
13 | {
14 | public:
15 | ThreadSafeQueue()
16 | {
17 |
18 | }
19 |
20 | ThreadSafeQueue(ThreadSafeQueue const& other)
21 | {
22 | std::lock_guard lock(other._mutex);
23 | _dataQueue = other._dataQueue;
24 | }
25 |
26 | ~ThreadSafeQueue()
27 | {
28 |
29 | }
30 |
31 | void push(T value)
32 | {
33 | std::lock_guard lock(_mutex);
34 | _dataQueue.push(value);
35 | _dataCond.notify_one();
36 | }
37 |
38 | bool waitAndPop(T& value)
39 | {
40 | std::unique_lock lock(_mutex);
41 | _dataCond.wait(lock);
42 | if (_dataQueue.empty())
43 | {
44 | return false;
45 | }
46 | value = _dataQueue.front();
47 | _dataQueue.pop();
48 | return true;
49 | }
50 |
51 | std::shared_ptr waitAndPop()
52 | {
53 | std::unique_lock lock(_mutex);
54 | _dataCond.wait(lock);
55 | if (_dataQueue.empty())
56 | {
57 | return nullptr;
58 | }
59 | std::shared_ptr res(std::make_shared(_dataQueue.front()));
60 | _dataQueue.pop();
61 | return res;
62 | }
63 |
64 | bool tryPop(T& value)
65 | {
66 | std::lock_guard lock(_mutex);
67 | if(_dataQueue.empty())
68 | return false;
69 |
70 | value = _dataQueue.front();
71 | _dataQueue.pop();
72 |
73 | return true;
74 | }
75 |
76 | std::shared_ptr tryPop()
77 | {
78 | std::lock_guard lock(_mutex);
79 | if(_dataQueue.empty())
80 | return std::shared_ptr();
81 | std::shared_ptr res(std::make_shared(_dataQueue.front()));
82 | _dataQueue.pop();
83 | return res;
84 | }
85 |
86 | size_t size() const
87 | {
88 | std::lock_guard lock(_mutex);
89 | return _dataQueue.size();
90 | }
91 |
92 | bool empty() const
93 | {
94 | std::lock_guard lock(_mutex);
95 | return _dataQueue.empty();
96 | }
97 |
98 | void clear()
99 | {
100 | std::lock_guard lock(_mutex);
101 | std::queue empty;
102 | _dataQueue.swap(empty);
103 | }
104 |
105 | void wake()
106 | {
107 | _dataCond.notify_one();
108 | }
109 |
110 | private:
111 | mutable std::mutex _mutex;
112 | std::queue _dataQueue;
113 | std::condition_variable _dataCond;
114 | };
115 |
116 | }
117 |
118 | #endif
119 |
120 |
--------------------------------------------------------------------------------
/src/net/Timer.cpp:
--------------------------------------------------------------------------------
1 | #include "Timer.h"
2 | #include
3 |
4 | using namespace xop;
5 | using namespace std;
6 | using namespace std::chrono;
7 |
8 | TimerId TimerQueue::AddTimer(const TimerEvent& event, uint32_t ms)
9 | {
10 | std::lock_guard locker(mutex_);
11 | int64_t timeout = GetTimeNow();
12 | TimerId timer_id = ++last_timer_id_;
13 |
14 | auto timer = make_shared(event, ms);
15 | timer->SetNextTimeout(timeout);
16 | timers_.emplace(timer_id, timer);
17 | events_.emplace(std::pair(timeout + ms, timer_id), std::move(timer));
18 | return timer_id;
19 | }
20 |
21 | void TimerQueue::RemoveTimer(TimerId timerId)
22 | {
23 | std::lock_guard locker(mutex_);
24 | auto iter = timers_.find(timerId);
25 | if (iter != timers_.end()) {
26 | int64_t timeout = iter->second->getNextTimeout();
27 | events_.erase(std::pair(timeout, timerId));
28 | timers_.erase(timerId);
29 | }
30 | }
31 |
32 | int64_t TimerQueue::GetTimeNow()
33 | {
34 | auto time_point = steady_clock::now();
35 | return duration_cast(time_point.time_since_epoch()).count();
36 | }
37 |
38 | int64_t TimerQueue::GetTimeRemaining()
39 | {
40 | std::lock_guard locker(mutex_);
41 |
42 | if (timers_.empty()) {
43 | return -1;
44 | }
45 |
46 | int64_t msec = events_.begin()->first.first - GetTimeNow();
47 | if (msec < 0) {
48 | msec = 0;
49 | }
50 |
51 | return msec;
52 | }
53 |
54 | void TimerQueue::HandleTimerEvent()
55 | {
56 | if(!timers_.empty()) {
57 | std::lock_guard locker(mutex_);
58 | int64_t timePoint = GetTimeNow();
59 | while(!timers_.empty() && events_.begin()->first.first<=timePoint)
60 | {
61 | TimerId timerId = events_.begin()->first.second;
62 | bool flag = events_.begin()->second->event_callback_();
63 | if(flag == true) {
64 | events_.begin()->second->SetNextTimeout(timePoint);
65 | auto timerPtr = std::move(events_.begin()->second);
66 | events_.erase(events_.begin());
67 | events_.emplace(std::pair(timerPtr->getNextTimeout(), timerId), timerPtr);
68 | }
69 | else {
70 | events_.erase(events_.begin());
71 | timers_.erase(timerId);
72 | }
73 | }
74 | }
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/src/net/Timer.h:
--------------------------------------------------------------------------------
1 | // PHZ
2 | // 2018-5-15
3 |
4 | #ifndef _XOP_TIMER_H
5 | #define _XOP_TIMER_H
6 |
7 | #include