TCP服务器程序在Mac与Ubuntu编译差异问题排查
首先,我看了你的代码,Mac上能编译过是因为Clang(Mac的默认编译器)对某些头文件的隐式包含比较宽松,而Ubuntu用的GCC更严格,加上代码里还有几个逻辑错误,导致编译失败。下面是具体问题和修复方案:
1. 缺失必要的头文件
你在DiscriptorNode的operator==里用了memcmp函数,但没有包含<cstring>头文件。Mac的编译器可能自动包含了这个头文件,但GCC不会,所以会报memcmp未定义的错误。
修复: 在StreamSwitch.h顶部添加:
#include <cstring>
2. remove函数的参数传递错误
你写的两个remove函数都是传值传递list:
void remove(list<DiscriptorNode> List, list<DiscriptorNode>:: iterator &Iterator)
这样函数里操作的是原list的副本,List.erase(temp)根本不会修改原来的Unconnected或Connected列表,而且还会导致迭代器失效的问题。
修复: 把list参数改成引用传递:
void remove(list<DiscriptorNode>& List, list<DiscriptorNode>::iterator& Iterator) { list<DiscriptorNode>::iterator temp = Iterator; Iterator++; List.erase(temp); } void remove(list<StreamConnection>& List, list<StreamConnection>::iterator& Iterator) { list<StreamConnection>::iterator temp = Iterator; Iterator++; List.erase(temp); }
3. StreamConnection的operator==逻辑错误
你写的StreamConnection的相等判断:
bool operator == (const StreamConnection& s) const { return this->FileDiscriptors == s.FileDiscriptors; }
这里FileDiscriptors是数组,数组名会退化成指针,所以你比较的是两个数组的地址,而不是数组里的文件描述符内容。这完全不符合你的预期,应该比较两个数组里的两个fd是否都相等。
修复: 修改成:
bool operator == (const StreamConnection& s) const { return (this->FileDiscriptors[0] == s.FileDiscriptors[0] && this->FileDiscriptors[1] == s.FileDiscriptors[1]) || (this->FileDiscriptors[0] == s.FileDiscriptors[1] && this->FileDiscriptors[1] == s.FileDiscriptors[0]); }
(这样不管两个fd的顺序,只要是同一对连接就算相等,符合你的业务逻辑)
4. setsockopt的返回值判断错误
在Begin函数里,你写的:
if (setsockopt(this->ServerFileDiscriptor, SOL_SOCKET, SO_REUSEADDR, &ReUseSocket, sizeof (ReUseSocket)) == 1) { return 1; }
setsockopt的返回值是0表示成功,-1表示失败,你现在判断等于1就返回,这完全反了,而且返回1(bool类型的话应该是true,但这里逻辑错误)。
修复: 修改成:
if (setsockopt(this->ServerFileDiscriptor, SOL_SOCKET, SO_REUSEADDR, &ReUseSocket, sizeof(ReUseSocket)) == -1) { perror("setsockopt failed"); return false; }
5. 代码截断导致的语法错误
你的StreamSwitch.cpp最后一行是截断的:
select(maximumFd,&ReadFileDiscriptors,&WriteFileDi
这明显没写完,应该补全select的完整参数:
int selectResult = select(maximumFd, &ReadFileDiscriptors, &WriteFileDiscriptors, &ExceptFileDiscriptors, &Timer_Variable); if (selectResult == -1) { perror("select failed"); return; }
之后还要处理select返回后的fd可读可写事件,比如处理新连接、客户端发的频道名称、数据转发等逻辑。
额外建议
- 尽量不要用
using namespace std;,尤其是头文件里,容易引发命名冲突,GCC有时候会因为这个报奇怪的错误。 - 对于
ChannelName的长度,用常量定义代替魔法数字1000,比如const int MAX_CHANNEL_NAME_LEN = 1000;,这样维护更方便。
把这些修改之后,你的程序应该能在Ubuntu上正常编译了。
内容的提问来源于stack exchange,提问作者Vinayak Shantaram Joshi

