網站首頁 編程語言 正文
起因
為什么要用C++的Thread,很簡單,因為我菜
一打五用pthread實現了socket多線程通信,我之前學并發的時候沒看pthread,因此代碼只能看個大概,后面還是要系統學一下pthread的
服務端
多線程功能放在騰訊云服務器上,代碼如下:
#include "tcpserver.h"
#include <thread>
#include <mutex>
TcpServer server;
mutex tcp_mutex;
void tcpFunc(int clientfd);
int main(int argc, char *argv[])
{
? ? if (server.initServer(6666) == false)
? ? {
? ? ? ? cout << "服務端初始化失敗!!!" << endl;
? ? ? ? return -1;
? ? }
? ? vector<thread> tcp_vec;
? ? while (true)
? ? {
? ? ? ? if (!server.tcpAccept())
? ? ? ? {
? ? ? ? ? ? continue;
? ? ? ? }
? ? ? ? tcp_vec.emplace_back(tcpFunc, server.m_connectfd);
? ? ? ? // thread tcpThread(tcpFunc, server.m_connectfd);
? ? ? ? // if (tcpThread.joinable())
? ? ? ? if(tcp_vec.back().joinable())
? ? ? ? {
? ? ? ? ? ? // cout << "Tcp thread " << tcpThread.get_id() << "is joinable!" << endl;
? ? ? ? ? ? cout << "Tcp thread " << tcp_vec.back().get_id() << " is joinable!" << endl;
? ? ? ? ? ? tcp_vec.back().detach();
? ? ? ? }
? ? }
? ? return 0;
}
void tcpFunc(int clientfd)
{
? ? int buf_len = 0;
? ? char buffer[1024];
? ? while (true)
? ? {
? ? ? ? unique_lock<mutex> tcplck(tcp_mutex);
? ? ? ? memset(buffer, 0, sizeof(buffer));
? ? ? ? if (!server.tcpRecv(clientfd, buffer, &buf_len, 5))
? ? ? ? {
? ? ? ? ? ? cout << "接收客戶端數據失敗!" << endl;
? ? ? ? ? ? tcplck.unlock();
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? cout << "服務端接收數據:" << buffer << endl;
? ? ? ? strcpy(buffer, "I am your father!");
? ? ? ? if (!server.tcpSend(clientfd, buffer, sizeof(buffer)))
? ? ? ? {
? ? ? ? ? ? cout << "向客戶端發送數據失敗!" << endl;
? ? ? ? ? ? tcplck.unlock();
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? tcplck.unlock();
?? ??? ??? ??? ?usleep(100);
? ? }
? ? cout << "通信異常!" << endl;
? ? return;
}
實在是很簡單,貽笑大方了
有幾個注意點:
- 全局變量在main函數執行完后會銷毀,線程中用到了全局變量server,線程detach后要保證數據的收發,就要保持server的生存期,這里體現為在main中循環等待客戶端的連接
- 要用鎖鎖住線程中server的操作,避免不同線程同時操作server造成混亂
- usleep(100);是為了避免不同線程爭搶同一把鎖而造成死鎖的發生
ROS客戶端
#include "tcpclient.h"
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
TcpClient client;
string send_str = "I am king of the world!";
char recv_buff[1024];
void client_callback(const geometry_msgs::Twist::ConstPtr &msg)
{
? ? cout << "vel X:" << msg->linear.x << ";vel Y:" << msg->linear.y << ";angular Z:" << msg->angular.z << endl;
? ? if (!client.tcpSend(client.m_sockfd, send_str.data(), send_str.size()))
? ? {
? ? ? ? cout << "向服務端發送報文失敗!" << endl;
? ? }
? ? if (!client.tcpRecv(client.m_sockfd, recv_buff, NULL, 10))
? ? {
? ? ? ? cout << "從服務端接收報文失敗!" << endl;
? ? }
? ? cout << "接收服務端報文:" << recv_buff << endl << endl;
}
int main(int argc, char **argv)
{
? ? ros::init(argc, argv, "joystick_client");
? ? ros::NodeHandle nh;
? ? string server_ip = "1.116.137.21";
? ? string loop_ip = "127.0.0.1";
? ? if (client.connectToServer(server_ip.data(), 6666) == false)
? ? {
? ? ? ? cout << "連接失敗!!!" << endl;
? ? ? ? return -1;
? ? }
? ? ros::Subscriber sub = nh.subscribe("/cmd_vel", 1, client_callback);
? ? ros::spin();
}
很簡單,訂閱了手柄發布的話題/cmd_vel,在回調函數中和服務端通訊
話題的發布頻率是10Hz,意味著和服務端通訊的頻率也是10Hz
普通客戶端
#include "tcp/tcpclient.h"
int main(int argc, char **argv)
{
? ? TcpClient client;
? ? string server_ip = "1.116.137.21";
? ? string loop_ip = "127.0.0.1";
? ? if (client.connectToServer(server_ip.data(), 6666) == false)
? ? {
? ? ? ? cout << "連接失敗!!!" << endl;
? ? ? ? return -1;
? ? }
? ? cout << "成功連接服務器!" << endl;
? ? char buff[1024];
? ? while (true)
? ? {
? ? ? ? memset(buff, 0, sizeof(buff));
? ? ? ? sprintf(buff, "Ouch!");
? ? ? ? if (!client.tcpSend(client.m_sockfd, buff, sizeof(buff)))
? ? ? ? {
? ? ? ? ? ? cout << "向服務端發送報文失敗!" << endl;
? ? ? ? ? ? return -1;
? ? ? ? }
? ? ? ? memset(buff, 0, sizeof(buff));
? ? ? ? if (!client.tcpRecv(client.m_sockfd, buff, NULL, 5))
? ? ? ? {
? ? ? ? ? ? cout << "從服務端接收報文失敗!" << endl;
? ? ? ? ? ? return -1;
? ? ? ? }
? ? ? ? cout << "接收服務端報文:" << buff << endl << endl;
? ? ? ? sleep(0.1);
? ? }
? ? return 0;
}
這里sleep(0.1);是為了模擬ROS中話題的頻率
sleep過長會導致服務端阻塞等待該客戶端的消息,從而導致其余客戶端與服務端的通信失敗(如果客戶端中允許的通信延時很短的話)
運行效果
云服務器上的服務端
[root@VM-4-11-centos bin]# ./server_thread?
Tcp thread 140662362572544 is joinable!
服務端接收數據:I am king of the world!
服務端接收數據:I am king of the world!
服務端接收數據:I am king of the world!
服務端接收數據:I am king of the world!
Tcp thread 140662354179840 is joinable!
服務端接收數據:I am king of the world!
服務端接收數據:Ouch!
服務端接收數據:I am king of the world!
服務端接收數據:Ouch!
服務端接收數據:I am king of the world!
服務端接收數據:Ouch!
服務端接收數據:I am king of the world!
服務端接收數據:Ouch!
筆記本上的ROS客戶端
redwall@redwall-G3-3500:~$ rosrun joystick_client joystick_client?
[ERROR] [1656939307.244367879]: [registerPublisher] Failed to contact master at [localhost:11311]. ?Retrying...
[ INFO] [1656939314.923909682]: Connected to master at [localhost:11311]
vel X:0;vel Y:0;angular Z:0
接收服務端報文:I am your father!vel X:0;vel Y:0;angular Z:0
接收服務端報文:I am your father!vel X:0;vel Y:0;angular Z:0
接收服務端報文:I am your father!
虛擬機的普通客戶端
- prejudice@prejudice-VirtualBox:~/socket_test/socket_for_linux/bin$ ./tcp_client 成功連接服務器!
- 接收服務端報文:I am your father!
- 接收服務端報文:I am your father!
- 接收服務端報文:I am your father!
不足
- 未考慮線程的清理
- 未考慮信號的退出處理
原文鏈接:https://blog.csdn.net/qq_34935373/article/details/125608828
相關推薦
- 2022-01-28 Hyper集成laravel中使用的blade模板
- 2023-07-26 webpack打包優化之減少代碼體積(Tree shaking、babel)
- 2022-03-24 樹莓派搭建nas服務器的詳細過程_Linux
- 2022-03-15 ant design: Instance created by `useForm` is not c
- 2022-12-28 Python標準庫之urllib和urllib3的使用及說明_python
- 2022-05-25 springboot整合jpa報錯詳解
- 2022-10-13 Python線性表種的單鏈表詳解_python
- 2022-11-29 redis配置文件詳解
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支