简体   繁体   English

在C ++类中包装Winsock函数

[英]Wrapping Winsock functions in C++ classes

I've seen some people creating a "is-a" relationship like the following: 我看到有些人创建了一个“is-a”关系,如下所示:

class TCPClient : public Socket
{
public:
    TCPClient(const std::string& host, unsigned short port);
};

where the Socket class implements Winsock functions such as Connect(), Close(), Bind() etc. Socket类实现Winsock函数,如Connect(),Close(),Bind()等。

Examples : 示例

But this doesn't feel natural to me who is a newbie in socket programming. 但对于我来说,这对插座编程的新手来说并不自然。

Does the above hierarchy make more logical sense than the following "has-a" counterpart? 上面的层次结构是否比下面的“has-a”对应物更具逻辑意义?

class TCPClient
{
public:
    TCPClient(const std::string& host, unsigned short port);
    ....
private:
    Socket m_socket;
};

A TCPClient uses a socket or has a socket, but is not itself a socket, and you wouldn't normally expect to be able to substitute a TCPClient anywhere a socket was expected. TCPClient使用套接字或具有套接字,但它本身不是套接字,并且通常不希望能够在预期的套接字的任何地方替换TCPClient。 As such, public inheritance doesn't make sense. 因此,公共继承没有意义。

You could use private inheritance for this case, but (at least in a typical case) it probably doesn't make much sense either. 可以在这种情况下使用私有继承,但(至少在典型情况下)它可能也没有多大意义。 Private inheritance makes sense primarily when the base class provides at least one virtual function you plan to override in the child class. 当基类提供至少一个您计划在子类中重写的虚函数时,私有继承才有意义。 If you have a virtual function and need to override it, you have no real choice but to use inheritance. 如果你有一个虚函数并需要覆盖它,你就没有真正的选择,只能使用继承。 I wouldn't expect a Socket class to have an virtual functions though; 我不希望Socket类有虚函数; that wouldn't normally apply here. 这通常不适用于此。

That basically leads to your second solution: the TCPClient should contain an instance of a Socket, rather than using inheritance at all. 这基本上导致了你的第二个解决方案:TCPClient应该包含一个Socket实例,而不是使用继承。

I should add, however, that the Socket class you've shown seems to conflate the notion of an actual socket with the notion of an address. 但是,我应该补充一点,你所展示的Socket类似乎将实际套接字的概念与地址的概念混为一谈。 My first socket class ( years ago) worked about like that, but since then I've concluded that it's not really an ideal design. 我的第一个套接字类( 年前 )工作有关这样,但从那时起,我的结论是,它不是一个真正理想的设计。 I've become convinced that it's worthwhile to keep the notion of an address separate from the socket itself. 我已经确信将地址的概念与套接字本身分开是值得的。 Though mine is a bit less elaborate, I find it interesting that what I came up with looks almost like it could have been the prototype from which Boost ASIO was derived. 虽然我的内容不那么复杂,但我觉得有趣的是,我提出的内容几乎就像它可能是Boost ASIO派生的原型。 It's a little smaller and simpler, but a lot of the basic ideas are generally pretty similar anyway. 它更小更简单,但无论如何,许多基本想法通常非常相似。

That leads to my next recommendation: take a look at Boost ASIO. 这导致了我的下一个建议:看看Boost ASIO。 Lacking a fairly specific reason to do otherwise, it's what I'd advise (and generally use) in most new code. 缺乏一个相当具体的理由,这是我在大多数新代码中建议(并且通常使用)的东西。 Although (as I said above) I've written several socket classes over the years, I haven't used any of them in much (any?) new code in quite a while now -- they really only have two possible advantages over ASIO. 虽然(正如我上面所说)我多年来编写了几个套接字类,但是我已经在很长一段时间内没有使用它们中的任何一个(任何?)新代码 - 它们实际上只比ASIO有两个可能的优势。 The first applies only to me: since I wrote and used them before ASIO existed, I already understand them and how they work. 第一个只适用于我:因为我在ASIO存在之前编写和使用它们,我已经理解它们以及它们是如何工作的。 The second may be similar: at least to me, they seem a little bit smaller and simpler (but, again, that may be just because I used them first). 第二个可能是相似的:至少对我来说,它们看起来更小更简单(但是,这可能只是因为我先使用它们)。 Even so, the advantages of (for example) using something other people already understand trumps those quite easily. 即便如此,(例如)使用其他人已经理解的东西的优点也很容易胜过这些。

Use has-a . 使用has-a A TCPClient uses a socket like a person uses a telephone. TCPClient使用类似于使用电话的人的套接字。 Would you derive a Person from a Telephone? 你会从电话中找到一个人吗?

class TCPClient : public Socket
{
public:
    TCPClient(const std::string& host, unsigned short port);
};

Network sockets are used not only in TCP/IP and the above design is more suitable if you plan to reuse your "Socket" class to implement other protocols using network sockets. 网络套接字不仅用于TCP / IP,如果您计划重用“Socket”类以使用网络套接字实现其他协议,则上述设计更合适。 For example: 例如:

class UDPClient : public Socket
{
};

I would say so. 我会这么说的。 Socket is an abstraction, a file descriptor (UNIX) or handle (Windows), which has resources associated with it and is managed by the operating system. Socket是一个抽象,一个文件描述符(UNIX)或句柄(Windows),它有与之关联的资源并由操作系统管理。 If we consider OSI model, the socket fits well into the presentation layer (it presents, or describes, a communication channel between two nodes), whereas a program that uses the socket sits on the application layer. 如果我们考虑OSI模型,套接字很好地适合表示层(它呈现或描述两个节点之间的通信通道),而使用套接字的程序则位于应用层。

Considering this, I would prefer not to inherit from the socket, unless I implement a kind of advanced socket (by analogy: C-pointer vs. smart pointer) to present and handle a logical connection and somehow manage the resources associated with the socket. 考虑到这一点,我宁愿不继承套接字,除非我实现一种高级套接字(通过类比:C指针与智能指针)来呈现和处理逻辑连接,并以某种方式管理与套接字关联的资源。 If XYZClient is an application, whose goal is to implement some business or data processing logic, I would not mix these two concepts together and use the second approach (has-a). 如果XYZClient是一个应用程序,其目标是实现一些业务或数据处理逻辑,我不会将这两个概念混合在一起并使用第二种方法(has-a)。

I would split infrastructure/resource-specific and business/application-specific logic. 我会拆分基础架构/资源特定的和业务/应用程序特定的逻辑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM