我需要一段代码才能正确进行多线程处理,并且不对我返回或崩溃。我该怎么办才能消耗任何return
或try/catch
块,以使main()
不结束?
我已经将cpp
与Google protobufs一起使用了很短的时间,但遇到了一个问题,但我无法尝试解决。我开始使用Google protobufs和this link的cpp
学习服务器-客户端套接字程序。我首先通过编辑.proto
文件将proto3
文件转换为.proto
。然后,我可以创建一个CMake文件来编译程序。
我需要制作一个新的客户端程序,以便在用server.cpp
取消Ctrl+c
时,客户端程序 NOT 不会崩溃,退出,段错误等。基本上,当服务器死机时,客户端应等待服务器重新联机。
我尝试了两件事:
boost
的多线程我尝试使用boost::thread
和boost::future
创建一个boost::async
。我在main()
中有一个循环,它将创建一个boost::async()
对象的矢量(长度为1),并用传递到boost::async()
构造函数中的方法来调用程序的其余部分。然后,我简单地用boost::wait_for_all()
和begin()
在迭代器上调用end()
。 This is where我有期货的想法。这是语法示例:
while (true)
{
printingmutex.lock();
cout << "------------------\nStarting initialization of socket.\n" << endl;
printingmutex.unlock();
// Now I create the threads.
std::vector<boost::future<void>> futures;
futures.push_back(boost::async([host_name]{ doSocketswag(host_name); }));
boost::wait_for_all(futures.begin(), futures.end());
// Delay function after disconnection, implementation irrelevant to the question
sleepApp(2000); // 2 seconds
}
为简便起见,这是新的.proto
文件,可转换为proto3
:
syntax = "proto3";
message log_packet {
fixed64 log_time = 1;
fixed32 log_micro_sec = 2;
fixed32 sequence_no = 3;
fixed32 shm_app_id = 4;
string packet_id = 5;
string log_level= 6;
string log_msg= 7;
}
这很重要,因为当我解决此问题后,我会将客户端程序移植到Ubuntu盒以外的其他平台,但是我仍将使用Ubuntu盒,并且我需要能够运行程序在消息发送之外进行操作。我还将能够向程序中添加GUI
,因此我将需要能够将套接字线程与程序的其余部分分开,从而防止不良连接杀死客户端程序。
如何使客户端程序成为多线程,以使套接字通信不会发生
main()
回来一个基本的,没有多余的装饰的实现即可显示套接字与主程序分开运行。
另外,为了加快响应速度,我有一个CMake文件来编译client
和server
和.proto
文件。我正在分享它,因此你们可以花更多的时间在实际回答问题上,而不是专门研究编译代码。
# Compiling the program, assuming all of the source files are in the same directory:
# mkdir build
# cd build
# cmake ..
# cmake --build . -- -j8 -l8
set(PROJECT_NAME CppProtobufdemo)
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(${PROJECT_NAME} LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_definitions(-std=c++11)
# CMAKE_CURRENT_SOURCE_DIR - This is the directory where CMake is running.
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/build)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)
find_package( Boost REQUIRED system thread timer chrono)
if(Boost_FOUND)
message("Boost was found.")
message(${Boost_INCLUDE_DIR})
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(THE_USER $ENV{USER})
message("This is the com user_:" ${THE_USER})
set(PROGRAMS_TO_COMPILE
server
client
)
# These lines are for autogenerating code from the *.proto files with CMake.
find_package(Protobuf REQUIRED)
if(PROTOBUF_FOUND)
message("Google Protobuf has been found.")
endif()
include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# https://cmake.org/cmake/help/git-master/module/FindProtobuf.html
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS message.proto)
# I want to see if I can access these proto files from python scripts
protobuf_generate_python(PROTO_PY message.proto)
foreach(aprogram ${PROGRAMS_TO_COMPILE})
add_executable(${aprogram} ${PROTO_SRCS} ${PROTO_HDRS} ${PROJECT_SOURCE_DIR}/${aprogram}.cpp )
target_link_libraries(${aprogram} ${Boost_LIBRARIES})
target_link_libraries(${aprogram} ${PROTOBUF_LIBRARIES})
endforeach()
另一件事:在此过程中,我总是摆脱了goto FINISH
语句。
如果您有任何意见或后续问题,我很乐意答复。
我尝试将这行换行
boost::wait_for_all(futures.begin(), futures.end());
在这样的尝试中捕获:
try {
// Now that I have created all of the threads, I need to wait for them to finish.
boost::wait_for_all(futures.begin(), futures.end());
}
catch (const std::exception& e)
{
// Just keep swimming
cout << "Thread died" << endl;
}
现在错误消息不被推送。相反,该程序只是退出,没有任何错误或任何消息。
我正在使用return
语句终止线程方法,但是它们不应终止main()
线程-除非我缺少其他内容。这是我用来演示此“修复程序”的客户端代码:
// This is for the futures functionality
#define BOOST_THREAD_VERSION 4
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
// cmake --build . -- -j8 -l8
#include "message.pb.h"
#include <iostream>
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
//
#include <boost/thread.hpp>
#include <chrono>
#include <thread>
using namespace google::protobuf::io;
using namespace std;
void doSocketSwag(void);
void sleepApp(int millis)
{
std::this_thread::sleep_for(std::chrono::milliseconds{millis});
}
// Boost sleep function
void wait(int milliseconds)
{
boost::this_thread::sleep_for(boost::chrono::milliseconds{milliseconds});
}
int main(int argv, char** argc)
{
// I will put this whole thing into a while loop
while (true)
{
cout << "Creating threads." << endl;
std::vector<boost::future<void>> futures;
// The socket thread
futures.push_back(boost::async([]{ doSocketSwag(); }));
// Now I need to catch exceptions
try {
// Now that I have created all of the threads, I need to wait for them to finish.
boost::wait_for_all(futures.begin(), futures.end());
}
catch (const std::exception& e)
{
// Just keep swimming
cout << "Thread died" << endl;
}
}
//delete pkt;
//FINISH:
//close(hsock);
return 0;
}
//
void doSocketSwag(void)
{
log_packet payload;
payload.set_log_time(10);
payload.set_log_micro_sec(10);
payload.set_sequence_no(1);
payload.set_shm_app_id(101);
payload.set_packet_id("TST");
payload.set_log_level("DEBUG");
payload.set_log_msg("What shall we say then");
//cout<<"size after serilizing is "<<payload.ByteSize()<<endl;
int siz = payload.ByteSize()+4;
char *pkt = new char [siz];
google::protobuf::io::ArrayOutputStream aos(pkt,siz);
CodedOutputStream *coded_output = new CodedOutputStream(&aos);
coded_output->WriteVarint32(payload.ByteSize());
payload.SerializeToCodedStream(coded_output);
int host_port= 1101;
char* host_name="127.0.0.1";
struct sockaddr_in my_addr;
char buffer[1024];
int bytecount;
int buffer_len=0;
int hsock;
int * p_int;
int err;
hsock = socket(AF_INET, SOCK_STREAM, 0);
if(hsock == -1){
printf("Error initializing socket %d\n",errno);
//goto FINISH;
return;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 ) || (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
printf("Error setting options %d\n",errno);
free(p_int);
//goto FINISH;
return;
}
free(p_int);
my_addr.sin_family = AF_INET ;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = inet_addr(host_name);
if( connect( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
if((err = errno) != EINPROGRESS){
fprintf(stderr, "Error connecting socket %d\n", errno);
//goto FINISH;
return;
}
}
while (true)
{
if( (bytecount=send(hsock, (void *) pkt,siz,0))== -1 ) {
// THIS is where the program dies.
fprintf(stderr, "Error sending data %d\n", errno);
//goto FINISH;
break;
}
//printf("Sent bytes %d\n", bytecount);
//usleep(1);
sleepApp(1000);
cout << "Thread slept for 1 second." << endl;
}
}
如果return
语句那么糟糕,我该如何替换它们?
答案 0 :(得分:0)
这是伙计们
查看Jeremy Friesner
提供的链接后,我发现此问题绝对不是原始问题。事实证明,套接字能够发布信号来中断cpp
程序,需要用户进行处理。 link provided解释了它是如何工作的。基本上,我只需要处理一个中断条件就可以使程序继续运行:程序中的逻辑是正确的,但是我对套接字的了解还不够多,无法询问SIGPIPE
和SIG_IGN
解决我的问题。我在下面显示了两个解决问题的示例,类似于Jeremy Friesner
的链接。多线程现在也可以正常工作,并且观看起来很棒。 ?
在此示例中,我直接从链接中复制解决方案:
// This is for the futures functionality
//#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_PROVIDES_FUTURE
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
// cmake --build . -- -j8 -l8
#include "message.pb.h"
#include <iostream>
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
//
#include <boost/thread.hpp>
#include <chrono>
#include <thread>
#include <signal.h>
using namespace google::protobuf::io;
using namespace std;
void doSocketSwag(void);
void sleepApp(int millis)
{
std::this_thread::sleep_for(std::chrono::milliseconds{millis});
}
// Boost sleep function
void wait(int milliseconds)
{
boost::this_thread::sleep_for(boost::chrono::milliseconds{milliseconds});
}
log_packet payload;
int siz;
char *pkt;
google::protobuf::io::ArrayOutputStream * aos;
CodedOutputStream *coded_output;
int host_port= 1101;
char* host_name="127.0.0.1";
struct sockaddr_in my_addr;
char buffer[1024];
int bytecount;
int buffer_len=0;
int hsock;
int * p_int;
int err;
// This boolean controls whether of not the socket thread loops.
std::atomic_bool dosockets{true};
// This is the mutex for printing
std::mutex printlock;
// Try to do client socket program without server.
int main(int argv, char** argc)
{
// Registering the singal PIPE ignore
signal(SIGPIPE, SIG_IGN);
// We build the packet.
payload.set_log_time(10);
payload.set_log_micro_sec(10);
payload.set_sequence_no(1);
payload.set_shm_app_id(101);
payload.set_packet_id("TST");
payload.set_log_level("DEBUG");
payload.set_log_msg("What shall we say then");
// Now I fill in the socket fields
siz = payload.ByteSize()+4;
pkt = new char [siz];
aos = new google::protobuf::io::ArrayOutputStream(pkt,siz);
coded_output = new CodedOutputStream(aos);
// Now we do methods on the objects
coded_output->WriteVarint32(payload.ByteSize());
payload.SerializeToCodedStream(coded_output);
// I will put this whole thing into a while loop
while (true)
{
printlock.lock();
cout << "Creating threads." << endl;
printlock.unlock();
std::vector<boost::future<void>> futures;
// The socket thread
futures.push_back(boost::async([]{ doSocketSwag(); }));
boost::wait_for_all(futures.begin(), futures.end());
}
//delete pkt;
//FINISH:
//close(hsock);
return 0;
}
//
void doSocketSwag(void)
{
//
while (dosockets)
{
printlock.lock();
cout << "Waiting to try again." << endl;
printlock.unlock();
sleepApp(1000);
hsock = socket(AF_INET, SOCK_STREAM, 0);
if(hsock == -1){
printlock.lock();
printf("Error initializing socket %d\n",errno);
printlock.unlock();
//goto FINISH;
continue;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 ) || (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
printlock.lock();
printf("Error setting options %d\n",errno);
printlock.unlock();
free(p_int);
//goto FINISH;
continue;
}
free(p_int);
my_addr.sin_family = AF_INET ;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = inet_addr(host_name);
if( connect( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
if((err = errno) != EINPROGRESS)
{
printlock.lock();
fprintf(stderr, "Error connecting socket %d\n", errno);
printlock.unlock();
//goto FINISH;
continue;
}
}
while (true)
{
if( (bytecount=send(hsock, (void *) pkt,siz,0))== -1 )
{
printlock.lock();
fprintf(stderr, "Error sending data %d\n", errno);
printlock.unlock();
//goto FINISH;
//break;
close(hsock);
break;
}
//printf("Sent bytes %d\n", bytecount);
//usleep(1);
sleepApp(1000);
printlock.lock();
cout << "Thread slept for 1 second." << endl;
printlock.unlock();
}
}
}
然后是在示例中,当SIGPIPE
信号发出时,我创建了一个回调函数:
// This is for the futures functionality
//#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_PROVIDES_FUTURE
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
// cmake --build . -- -j8 -l8
#include "message.pb.h"
#include <iostream>
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
//
#include <boost/thread.hpp>
#include <chrono>
#include <thread>
#include <signal.h>
using namespace google::protobuf::io;
using namespace std;
void doSocketSwag(void);
void sleepApp(int millis)
{
std::this_thread::sleep_for(std::chrono::milliseconds{millis});
}
// Boost sleep function
void wait(int milliseconds)
{
boost::this_thread::sleep_for(boost::chrono::milliseconds{milliseconds});
}
log_packet payload;
int siz;
char *pkt;
google::protobuf::io::ArrayOutputStream * aos;
CodedOutputStream *coded_output;
int host_port= 1101;
char* host_name="127.0.0.1";
struct sockaddr_in my_addr;
char buffer[1024];
int bytecount;
int buffer_len=0;
int hsock;
int * p_int;
int err;
// This boolean controls whether of not the socket thread loops.
std::atomic_bool dosockets{true};
// This is the mutex for printing
std::mutex printlock;
// The signal pipe error
void my_handler(int input)
{
// Simply print
printlock.lock();
cout << "I got into the pipe handler LOOK AT ME WOOO HOOO." << endl;
printlock.unlock();
}
// Try to do client socket program without server.
int main(int argv, char** argc)
{
// Registering the singal PIPE ignore
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = my_handler;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGPIPE, &sigIntHandler, NULL);
// We build the packet.
payload.set_log_time(10);
payload.set_log_micro_sec(10);
payload.set_sequence_no(1);
payload.set_shm_app_id(101);
payload.set_packet_id("TST");
payload.set_log_level("DEBUG");
payload.set_log_msg("What shall we say then");
// Now I fill in the socket fields
siz = payload.ByteSize()+4;
pkt = new char [siz];
aos = new google::protobuf::io::ArrayOutputStream(pkt,siz);
coded_output = new CodedOutputStream(aos);
// Now we do methods on the objects
coded_output->WriteVarint32(payload.ByteSize());
payload.SerializeToCodedStream(coded_output);
// I will put this whole thing into a while loop
while (true)
{
printlock.lock();
cout << "Creating threads." << endl;
printlock.unlock();
std::vector<boost::future<void>> futures;
// The socket thread
futures.push_back(boost::async([]{ doSocketSwag(); }));
boost::wait_for_all(futures.begin(), futures.end());
}
//delete pkt;
//FINISH:
//close(hsock);
return 0;
}
//
void doSocketSwag(void)
{
//
while (dosockets)
{
printlock.lock();
cout << "Waiting to try again." << endl;
printlock.unlock();
sleepApp(1000);
hsock = socket(AF_INET, SOCK_STREAM, 0);
if(hsock == -1){
printlock.lock();
printf("Error initializing socket %d\n",errno);
printlock.unlock();
//goto FINISH;
continue;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 ) || (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
printlock.lock();
printf("Error setting options %d\n",errno);
printlock.unlock();
free(p_int);
//goto FINISH;
continue;
}
free(p_int);
my_addr.sin_family = AF_INET ;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = inet_addr(host_name);
if( connect( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
if((err = errno) != EINPROGRESS)
{
printlock.lock();
fprintf(stderr, "Error connecting socket %d\n", errno);
printlock.unlock();
//goto FINISH;
continue;
}
}
while (true)
{
if( (bytecount=send(hsock, (void *) pkt,siz,0))== -1 )
{
printlock.lock();
fprintf(stderr, "Error sending data %d\n", errno);
printlock.unlock();
//goto FINISH;
//break;
close(hsock);
break;
}
//printf("Sent bytes %d\n", bytecount);
//usleep(1);
sleepApp(1000);
printlock.lock();
cout << "Thread slept for 1 second." << endl;
printlock.unlock();
}
}
}
服务器代码与问题开头提供的original link相同。
谢谢你们的评论。他们将我引向我的答案,以及cpp
的全新领域,我不知道是什么signal
。
(如果你们想继续发表评论,那也很好。我认为这个问题已经得到回答。)