对github上用C++实现webrtc的peerconnection的example的解析
在寻找WebRTC实现的过程中,找到了一个github上用C++的实现,感觉不错,特此记录学习。WebRTC的具体原理,参考以下链接,本文主要记录该例子在C++中如何实现。下图是该例子的大纲,分为client和server两个部分。
前言
在寻找WebRTC实现的过程中,找到了一个github上用C++的实现,感觉不错,特此记录学习。
WebRTC的具体原理,参考以下链接,本文主要记录该例子在C++中如何实现。
https://antmedia.io/webrtc-signaling-servers-everything-you-need-to-know/
下图是该例子的大纲,分为client和server两个部分。
Server
除main以外的文件用途
Data_socket
用于创建数据包,提供发送和解析的功能
Peer_channel
用来判断peer_connection是否连接成功,提供一些对channel的操作,可以同时和多个client连接
需要peer_id来对client进行区分
###Util
提供了int转换到string和size_t转换到string的功能
server端main函数
void HandleBrowserRequest(DataSocket* ds, bool* quit) {
assert(ds && ds->valid());
assert(quit);
const std::string& path = ds->request_path();
*quit = (path.compare("/quit") == 0);
if (*quit) {
ds->Send("200 OK", true, "text/html", "",
"<html><body>Quitting...</body></html>");
} else if (ds->method() == DataSocket::OPTIONS) {
// We'll get this when a browsers do cross-resource-sharing requests.
// The headers to allow cross-origin script support will be set inside
// Send.
ds->Send("200 OK", true, "", "", "");
} else {
// Here we could write some useful output back to the browser depending on
// the path.
printf("Received an invalid request: %s\n", ds->request_path().c_str());
ds->Send("500 Sorry", true, "text/html", "",
"<html><body>Sorry, not yet implemented</body></html>");
}
}
int main(int argc, char* argv[]) {
absl::SetProgramUsageMessage(
"Example usage: ./peerconnection_server --port=8888\n");
absl::ParseCommandLine(argc, argv);
// InitFieldTrialsFromString stores the char*, so the char array must outlive
// the application.
const std::string force_field_trials = absl::GetFlag(FLAGS_force_fieldtrials);
webrtc::field_trial::InitFieldTrialsFromString(force_field_trials.c_str());
int port = absl::GetFlag(FLAGS_port);
// Abort if the user specifies a port that is outside the allowed
// range [1, 65535].
if ((port < 1) || (port > 65535)) {
printf("Error: %i is not a valid port.\n", port);
return -1;
}
ListeningSocket listener;
if (!listener.Create()) {
printf("Failed to create server socket\n");
return -1;
} else if (!listener.Listen(port)) {
printf("Failed to listen on server socket\n");
return -1;
}
printf("Server listening on port %i\n", port);
PeerChannel clients;
typedef std::vector<DataSocket*> SocketArray;
SocketArray sockets;
bool quit = false;
while (!quit) {
// fd_set有两个成员变量,fd_count数据类型是unsingled int,fd_array[64]是unsingled int64
fd_set socket_set;
// 将socket_set的fd_count清空
FD_ZERO(&socket_set);
if (listener.valid())
// 在count<64的情况下,将新监听到的client的socket添加到fd_array中
FD_SET(listener.socket(), &socket_set);
for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
FD_SET((*i)->socket(), &socket_set);
struct timeval timeout = {10, 0};
if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
printf("select failed\n");
break;
}
for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) {
DataSocket* s = *i;
bool socket_done = true;
// 检查当前的socket是否在socket_set里
if (FD_ISSET(s->socket(), &socket_set)) {
// 判断是否接收到header,从client处接收到信息
if (s->OnDataAvailable(&socket_done) && s->request_received()) {
ChannelMember* member = clients.Lookup(s);
// 判断是否peer_connected
if (member || PeerChannel::IsPeerConnection(s)) {
if (!member) {
if (s->PathEquals("/sign_in")) {
clients.AddMember(s);
} else {
printf("No member found for: %s\n", s->request_path().c_str());
s->Send("500 Error", true, "text/plain", "",
"Peer most likely gone.");
}
} else if (member->is_wait_request(s)) {
// no need to do anything.
socket_done = false;
} else { // 如果socket尚未添加到set里
ChannelMember* target = clients.IsTargetedRequest(s); // 根据peer_id来进行判断,如果存在,返回一个client
if (target) {
// 向client发送request,来创建peer_connection
member->ForwardRequestToPeer(s, target);
} else if (s->PathEquals("/sign_out")) {
s->Send("200 OK", true, "text/plain", "", "");
} else {
printf("Couldn't find target for request: %s\n",
s->request_path().c_str());
s->Send("500 Error", true, "text/plain", "",
"Peer most likely gone.");
}
}
} else { // 既不在set里,也没有达成peer_connection
// 根据DataSocket,发送相对应的内容
HandleBrowserRequest(s, &quit);
if (quit) { // 在HandleBrowserRequest中,会对quit做一些判断,如果为false,清除socket并关闭所有的listerner和clients
printf("Quitting...\n");
FD_CLR(listener.socket(), &socket_set);
listener.Close();
clients.CloseAll();
}
}
}
} else {
socket_done = false;
}
if (socket_done) { // socket完成,接受完该socket后,将连接断掉
printf("Disconnecting socket\n");
clients.OnClosing(s);
assert(s->valid()); // Close must not have been called yet.
FD_CLR(s->socket(), &socket_set);
delete (*i);
i = sockets.erase(i);
if (i == sockets.end())
break;
}
}
// check timeout
clients.CheckForTimeout();
// 服务器端socket处理
if (FD_ISSET(listener.socket(), &socket_set)) {
DataSocket* s = listener.Accept();
if (sockets.size() >= kMaxConnections) {
delete s; // sorry, that's all we can take.
printf("Connection limit reached\n");
} else {
sockets.push_back(s);
printf("New connection...\n");
}
}
}
// 释放资源
for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
delete (*i);
sockets.clear();
return 0;
}
主要步骤
- 解析命令行
- 设置port
- 监听socket
- 通过PeerChannel来实现对client端的一对多的控制
- SockerArray来实现对若干个(数量小于64)socket的相关操作
- 主要loop
6.1 通过遍历SocketArray来实现socket的解析
6.2 遍历完成后,将接收到的新的socket添加到socketArray中,以待loop中的下一次循环 - 释放资源
Client端
除main以外的文件用途
conductor
初始化peer_connection并执行相关操作,包括但不限于创建,删除,修改peer_connection,对track和channel的修改
default
提供相关的默认值
flag_defs
为client端的peer_connection提供测试信号
main_wnd
wnd由HWND声明,是windows_handle,窗口句柄,用以程序与用户的交互,并实现UI部分
peer_connection_client
与client相关的操作,也包括client的相关状态
一些根据状态改变进行的操作,如OnClose(),OnRead()
main
// Main loop.
MSG msg;
BOOL gm;
while ((gm = ::GetMessage(&msg, NULL, 0, 0)) != 0 && gm != -1) {
if (!wnd.PreTranslateMessage(&msg)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
if (conductor->connection_active() || client.is_connected()) {
while ((conductor->connection_active() || client.is_connected()) &&
(gm = ::GetMessage(&msg, NULL, 0, 0)) != 0 && gm != -1) {
if (!wnd.PreTranslateMessage(&msg)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
}
rtc::CleanupSSL();
return 0;
}
主要实现在连接成功且client端成功连接到server端时,接收来自server端的socket
link to github
更多推荐
所有评论(0)