我在Windows XP(SP3)下遇到的情况让我疯狂,而且我已经到了我的系绳的末端,所以也许有人可以提供一些灵感.
我有一个C++网络程序(非GUI).该程序用于在Windows,MacOS/X和Linux下编译和运行,因此它使用select()和非阻塞I/O作为其事件循环的基础.
除了网络功能外,该程序还需要从stdin读取文本命令,并在stdin关闭时正常退出.在Linux和MacOS/X下,这很容易 - 我只是在我的read fd_set中包含STDIN_FILENO来select(),而select()在stdin关闭时返回.我检查FD_ISSET(STDIN_FILENO,&readSet)是否为真,尝试从stdin读取一些数据,recv()返回0/EOF,所以我退出进程.
另一方面,在Windows下,您无法选择STDIN_FILE_HANDLE,因为它不是真正的套接字.您也不能对STDIN_FILE_HANDLE执行非阻塞读取.这意味着无法从主线程读取stdin,因为ReadFile()可能无限期地阻塞,导致主线程停止提供其网络功能.
没问题,我说,我只会产生一个线程来处理stdin.该线程将在无限循环中运行,在ReadFile(stdinHandle)中阻塞,并且只要ReadFile()返回数据,stdin线程就会将该数据写入TCP套接字.该套接字的另一端将由主线程选择(),因此主线程将看到通过连接进入的stdin数据,并以与其他任何操作系统相同的方式处理"stdin".如果ReadFile()返回false以指示stdin已关闭,则stdin-thread仅关闭其套接字对的结尾,以便主线程将通过select()通知,如上所述.
当然,Windows不会有一个很好的socketpair()函数,所以我不得不推出自己用听(),连接(),并接受()(如见于CreateConnectedSocketPair()函数在这里,但我做到了一般而言,它似乎有效.
问题是它不能100%工作.特别是,如果stdin在程序启动的几百毫秒内关闭,大约一半时间主线程没有得到任何关于套接字对的stdin-end已经关闭的通知.我的意思是,我可以看到(通过我的printf() - 调试)stdin线程在其套接字上调用closesocket(),我可以看到主线程是select() - 关联socket(即套接字对的另一端),但是select()永远不会返回......如果它确实返回,由于某些其他套接字选择了ready-for-whatever,FD_ISSET(main_thread_socket_for_socket_pair,&readSet)返回0,好像连接没有关闭.
在这一点上,我唯一的假设是Windows的select()实现中存在一个错误,导致主线程的select()没有注意到套接字对的另一端已被stdin-thread关闭.有另一种解释吗?(请注意,此问题已在Windows 7下报告,尽管我没有在该平台上亲自查看过它)
我在这里为bash脚本专家提供了一些小问题...我有一个bash脚本,需要在运行时创建一个小的(80字节)二进制文件.文件的内容需要包含在脚本本身内(即我不想只是将文件与脚本一起打包).
我的脚本目前这样做:
echo 'begin-base64 644 dummy.wav' > /tmp/dummy.uu
echo 'UklGRkgAAABXQVZFZm10IBAAAAADAAEAAHcBAADcBQAEACAAZmFjdAQAAAAAAAAAUEVBSxAAAAAB' >> /tmp/dummy.uu
echo 'AAAAQDYlTAAAAAAAAAAAZGF0YQAAAAA=' >> /tmp/dummy.uu
echo '====' >> /tmp/dummy.uu
uudecode -o /tmp/dummy.wav /tmp/dummy.uu
rm /tmp/dummy.uu
Run Code Online (Sandbox Code Playgroud)
...在上面的运行之后,我有我的文件/tmp/dummy.wav.但我刚刚发现这个脚本运行的计算机没有安装uudecode(我不允许安装它),所以我需要找到一些其他的方法来创建这个文件.有任何想法吗?
我有一些代码,我已成功使用多年来实现"变体类型对象"; 也就是说,一个C++对象可以保存各种类型的值,但只使用(大约)尽可能多的内存作为最大的可能类型.该代码在精神上类似于tagged-union,但它也支持非POD数据类型.它通过使用char缓冲区,placement new/delete和reinterpret_cast <>来实现这种魔力.
我最近尝试在gcc 4.4.3(带-O3和-Wall)下编译这段代码,并得到了很多这样的警告:
warning: dereferencing type-punned pointer will break strict-aliasing rules
Run Code Online (Sandbox Code Playgroud)
从我读过的内容来看,这表明gcc的新优化器可能会生成'buggy'代码,我显然希望避免这种代码.
我在下面粘贴了我的代码的"玩具版"; 我可以对我的代码做些什么来使它在gcc 4.4.3下更安全,同时仍然支持非POD数据类型?我知道作为最后的手段,我总是可以使用-fno-strict-aliasing编译代码,但是如果代码在优化下没有中断会更好,所以我宁愿不这样做.
(注意,我想避免在代码库中引入boost或C++ 0X依赖,所以虽然boost/C++ 0X解决方案很有趣,但我更喜欢更老式的东西)
#include <new>
class Duck
{
public:
Duck() : _speed(0.0f), _quacking(false) {/* empty */}
virtual ~Duck() {/* empty */} // virtual only to demonstrate that this may not be a POD type
float _speed;
bool _quacking;
};
class Soup
{
public:
Soup() : _size(0), _temperature(0.0f) {/* empty */}
virtual ~Soup() {/* empty */} // virtual only to demonstrate that this …Run Code Online (Sandbox Code Playgroud) 我正在努力为我的服务器程序添加OpenSSL支持,并且通常它工作得很好,但我遇到了一个问题.
首先,一些背景知识:服务器是单线程的,使用非阻塞I/O和select()循环来同时处理多个客户端.服务器链接到libssl.0.9.8.dylib和lib crypto.0.9.8.dylib(即MacOS/X 10.8.5在/ usr/lib中提供的库).客户端< - >服务器协议是专有的全双工消息传递协议; 也就是说,客户端和服务器都可以随时发送和接收数据,并且客户端< - >服务器TCP连接无限期地保持连接(即直到客户端或服务器决定断开连接).
问题是:我的客户端可以连接到服务器,发送和接收数据工作正常(现在我已经整理了SSL_ERROR_WANT_WRITE和SSL_ERROR_WANT_READ逻辑)...但是如果服务器接受()'是新客户端连接而其他客户端在发送或接收数据的过程中,SSL层似乎破裂了.特别是,在服务器运行SetupSSL()例程(如下所示)以设置新接受的套接字之后,在一个或多个其他(预先存在的)客户端套接字上的SSL_read()将立即返回-1,并且ERR_print_errors_fp(stderr)给出了这个输出:
SSL_read() ERROR: 5673:error:140F3042:SSL routines:SSL_UNDEFINED_CONST_FUNCTION:called a function you should not call:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/ssl_lib.c:2248:
Run Code Online (Sandbox Code Playgroud)
首次出现此错误后,服务器很大程度上停止工作.数据移动停止,如果我尝试连接另一个客户端,我经常会收到此错误:
SSL_read() ERROR: 5673:error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/s23_srvr.c:578:
Run Code Online (Sandbox Code Playgroud)
在我的测试场景中,这种情况大约占25%.如果我确保在新客户端连接时我的预先存在的客户端连接是空闲的(没有数据被发送或接收),它永远不会发生.有谁知道这里可能出了什么问题?我找到了一个OpenSSL错误,还是有一些我忽略的细节?我的程序中的一些相关代码粘贴在下面,以防它有用.
// Socket setup routine, called when the server accepts a new TCP socket
int SSLSession :: SetupSSL(int sockfd)
{
_ctx = SSL_CTX_new(SSLv23_method());
if (_ctx)
{
SSL_CTX_set_mode(_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
_ssl = SSL_new(_ctx);
if (_ssl)
{
_sbio = BIO_new_socket(sockfd, BIO_NOCLOSE);
if (_sbio)
{
SSL_set_bio(_ssl, _sbio, _sbio);
SSL_set_accept_state(_ssl);
BIO_set_nbio(_sbio, !blocking);
ERR_print_errors_fp(stderr);
return RESULT_SUCCESS;
} …Run Code Online (Sandbox Code Playgroud) 今天我遇到了一些包含#ifdef子句的C++代码,如下所示:
#ifdef DISABLE_UNTIL OTHER_CODE_IS_READY
foo();
#endif
Run Code Online (Sandbox Code Playgroud)
请注意"DISABLE_UNTIL"和"OTHER_CODE_IS_READY"之间的空格.基本上#ifdef行中指定了两个标记.
我的问题是,这是合法的C++代码吗?(g ++编译它没有任何错误,它显然只是忽略了第二个标记).如果它是合法的,第二个令牌是否会产生任何影响?
我有我的模板化容器类,如下所示:
template<
class KeyType,
class ValueType,
class KeyCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<KeyType>,
class ValueCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<ValueType>
>
class MyClass
{
[...]
}
Run Code Online (Sandbox Code Playgroud)
这意味着当我实例化这个类的对象时,我可以通过几种不同的方式来实现:
MyClass<MyKeyType, MyValueType> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor, MyCustomValueCompareFunctor> myObject;
Run Code Online (Sandbox Code Playgroud)
这些都很好.当我想要实例化使用ValueCompareFunctor参数的非默认版本的MyClass时,问题出现了,但我仍然想使用KeyCompareFunctor参数的默认值.然后我要写这个:
MyClass<MyKeyType, MyValueType, AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>, MyCustomValueCompareFunctor> myObject;
Run Code Online (Sandbox Code Playgroud)
如果我能以某种方式省略第三个参数并且只写下这个会更方便:
MyClass<KeyType, ValueType, MyCustomValueCompareFunctor> myObject;
Run Code Online (Sandbox Code Playgroud)
由于MyCustomValueCompareFunctor仅适用于MyValueType类型的对象而不适用于MyKeyType类型的对象,因此编译器似乎至少在理论上可以解决我的意思.
有没有办法在C++中执行此操作?
我有一个包含错误的可执行文件(C++,i386,在 MacOS/X Tiger 下编译,如果重要的话)。该错误的修复很简单——代码中有一个地方调用 fork() 而它不应该。因为修复很简单,而且因为此时从头开始重新编译可执行文件会很困难(不要问),我想直接修补可执行文件/二进制文件。
作为迈出的第一步,我在我的可执行文件上运行了“otool -tV MyExecutableName”,瞧,我在反汇编输出中发现了这个:
./MyExecutableName:
(__TEXT,__text) section
[... many lines omitted ...]
0002ce0d subl $0x10,%esp
0002ce10 calll 0x0051adac
0002ce15 movzbl 0x14(%ebp),%esi
0002ce19 calll 0x00850ac9 ; symbol stub for: _fork
0002ce1e cmpl $0x00,%eax
0002ce21 jll 0x0002cf02
0002ce27 jle 0x0002ce34
[... many more lines omitted ...]
Run Code Online (Sandbox Code Playgroud)
所以我想做的是替换第 0002ce19 行的操作码,这样它就不会调用 _fork,而是无条件地跳转到失败情况(即它应该像 fork() 返回 -1 一样)
不幸的是,我在反汇编/二进制补丁方面是一个完全的新手,所以我不确定如何去做。特别是,我的问题是:
1)我应该将哪些字节写入位置 0002ce19 到 0002xe1d 以获得我想要的?我假设它是“jmp 0x0002cf02”的组装等价物,但我如何弄清楚这些字节是什么?
2) "otool -tV" 打印的偏移量似乎是到可执行文件的 __TEXT 段的偏移量。如何找出打印偏移量和文件顶部之间的字节增量,以便我可以编辑/修补文件中的正确字节?
感谢您提供的任何建议!
我正在尝试理解选择IPv6多播地址组ID的规则,并且RFC似乎有些不一致.例如,在RFC 2373第2.7节中显示了此图:
| 8 | 4 | 4 | 112 bits |
+------ -+----+----+---------------------------------------------+
|11111111|flgs|scop| group ID |
+--------+----+----+---------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
......但是在第2.7.2节中它显示了这个:
| 8 | 4 | 4 | 80 bits | 32 bits |
+------ -+----+----+---------------------------+-----------------+
|11111111|flgs|scop| reserved must be zero | group ID |
+--------+----+----+---------------------------+-----------------+
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,Group ID字段的高80位是否可用?如果它们可用,是否仅在某些情况下(例如,当使用非以太网网络技术时?)如果我在通过以太网LAN进行多播时设置这些位,我应该遇到什么问题?
我已经在我的Qt应用程序的Windows版本中添加了一个迷你核心转储功能(通过__try/__ except和MiniDumpWriteDump()),这样如果/当我的应用程序崩溃时,.dmp文件将被写入磁盘让我以后查看和调试.
这非常有效,但是对于测试,我希望有一个已知可靠的方法来使我的程序崩溃.例如,GUI中可能存在"立即崩溃"按钮,当用户单击它时,它将导致应用程序故意崩溃.
当然,一种方法是这样的:
int * badPointer = NULL;
*badPointer = 666;
Run Code Online (Sandbox Code Playgroud)
这对我有用,但我不喜欢这种方法,因为它依赖于未定义的行为 - 特别是,C++标准不要求上面的代码导致崩溃,所以它是可能的(从语言 - 律师的角度来看) )当上面的代码执行时,编译器的某些未来版本不会崩溃.
作为一种更"官方"的方法,我试过这个:
abort();
Run Code Online (Sandbox Code Playgroud)
...它会终止程序,但它不会导致Windows结构化异常触发MiniCrashDump处理程序,因此不会写入.dmp文件.
我的问题是,是否有一个"官方正确的方式"来破坏我的计划?我看到Windows API有一个我可以调用的RaiseException()函数,但我不确定它应该是什么正确的参数.这是要走的路,还是有一些更具体的电话,我会更好用?
我刚才注意到,当我使用 pthread_create() 生成线程时,我为线程设置自定义堆栈大小的请求似乎被忽略了。特别是,如果我从生成的线程中调用 pthread_attr_getstacksize() ,它总是报告默认堆栈大小,无论我要求什么。
这种行为在 Linux 和 MacOS/X 下都会出现,所以我怀疑我做错了什么,但我不知道它是什么。
要重现该问题,请编译并运行下面的代码(通过“g++ stack_test.cpp -lpthread ; ./a.out”)。它会尝试一堆不同的堆栈大小,如果其请求未得到满足,则会发出抱怨。有问题的输出如下所示:
Jeremys-Mini:~ lcsuser1$ ./a.out
Testing creation of a thread with stack size: 8192
ThreadFunc: ERROR, wrong stack size! (Requested: 8192, got: 524288)
Testing creation of a thread with stack size: 16384
ThreadFunc: ERROR, wrong stack size! (Requested: 16384, got: 524288)
Testing creation of a thread with stack size: 24576
ThreadFunc: ERROR, wrong stack size! (Requested: 24576, got: 524288)
[...]
Testing creation of a thread with stack …Run Code Online (Sandbox Code Playgroud)