我的网络开发之旅——socket编程

简介:

上一篇文章《TCP/IP协议分析》讲述了自己是如何和网络领域的开发扯上关系的。正如从招聘网站上抽出的几个关键词“TCP/IP, Socket, 多线程”可见,协议分析并不是网络开发的主流,通常我们所说的网络编程是socket编程。今天就以我的经历来讲一下socket编程的相关知识。


socket编程的基础知识我就不在这里科普了,大家可以通过相关书籍和资料去了解。

socket编程难吗

在招聘工程师时面试问到某些新人这个问题。他们以为会编写客户端/服务端建立连接正常收发数据的流程就认为自己了解socket开发。真是这样简单调用几个API,理解下三次握手,会使用bind、listen、......就可以了吗?

当然不是,随着客户端数量的增加,少量并发——>大量并发——>海量并发的过程中服务端的处理难度也会随之增加。在服务端编程中非常有名的C10K问题(网络服务在处理数以万计的客户端连接时,往往出现效率低下甚至完全瘫痪)就向我们做了很详细的说明。但是客户端socket编程虽然没有这种并发要求就一定简单吗?我认为不是的。请参看我的这篇文章《客户端网络库实现真的很简单吗》。另外互联网中各种复杂的网络环境也会给我们进行socket编程带来很多困难和挑战。

所以总体来说想要做好socket编程还是有一定难度的。大家很容易从各种招聘渠道了解到精通这个领域的人在市场上很热销,报酬也很可观,而且多为一些互联网巨头和新兴互联网公司所需要。

服务端的网络模型

要想处理我们上面所说的C10K甚至C100K问题,网络模型的选择是非常重要的。那么我们首先要清楚几个概念:阻塞I/O,非阻塞I/O,I/O复用,异步I/O 。网络上关于这个话题的讨论有很多,我说说我的理解吧:

  • 阻塞/非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要睡眠等待。

  • 同步/异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞。异步只需要得到I/O操作完成的通知,并不主动读写数据,而是由操作系统去完成数据的读写。

所以可以看出阻塞I/O,非阻塞I/O,I/O复用都属于同步的范畴。

常见的几种服务端网络模型:

  • all connections one thread+blocking I/O:服务端对所有客户端连接只用一个线程去处理。而且网络I/O还是阻塞的。这在多并发情况下就是找死,吞吐率会很低,延迟会非常大。

  • per connection per thread+blocking I/O:服务端线程资源是有限的,而且线程的上下文切换是很耗资源的,随着客户端并发连接的增多系统资源也会慢慢吃紧。但是在这种模型的基础上,有些语言内置的协程(用户级线程)却可以解决资源问题。比如Go routine, Erlang actor。前几天刚发现了一个基于C语言的协程库state thread也可以用来实现用户级线程。

  • thread pool+blocking I/O:线程池的方式依然会受制于服务器CPU个数,自然也不会高效的。

  • non-blocking I/O + I/O multiplexing:网络I/O的多路复用,正是解决C10K问题最基础的方案。但是还可以进一步优化吗?

  • non-blocking I/O + I/O multiplexing + asyc I/O:非常理想、高效的网络模型。windows下是利用完成端口来帮我们实现这个模型,linux下要依赖异步I/O机制,但是究竟是否好用我没尝试过。

从上面又引出了两种高性能的服务端网络编程设计模式:基于I/O事件驱动的Reactor和基于异步I/O驱动的Proactor。其中non-blocking I/O + I/O multiplexing属于Reactor模式。non-blocking I/O + I/O multiplexing + asyc I/O属于Proactor模式。

重点介绍下non-blocking I/O + I/O multiplexing

今天我们所讲的只基于linux平台。毕竟linux平台的服务器占据了市场份额的90%以上。linux下目前最成熟的模型是epoll。(说到这给大家提个问题:epoll和它的老前辈select有什么不同呢?)

刚才讲到non-blocking I/O + I/O multiplexing时,提到过在此模型的基础上我们还可以优化吗?可以的。我们可以采用一个线程对应一个事件循环的机制启用多个线程。毕竟现在的服务器硬件资源是很强大的,我们不要浪费了多cpu资源。这就引出了我们要讲的另一个概念:master—worker模型。字面上的理解就是有一个master负责协调工作,由好几个worker去实际完成工作。在这种编程模型中:也就是有一个master负责将客户端连接分发给不同的worker线程,或者通知连接来了由worker去抢占,实际上由worker去完成客户端连接的读写或逻辑处理工作。这样不但有效利用了服务器的CPU资源,也增加了服务端的吞吐量,降低了客户端的延迟。更详细的讲解请参见我的文章《从master-worker模型看团队管理》 。

一些知名的第三方网络库

站在巨人的肩膀上可以让我们看得更为高远,如果选用了合适的第三方网络库也会使我们的工作事半功倍。

  • ACE学之者生用之者死。这是陈硕老师对ACE库的评价,我觉得很形象。对于学院派理想化的东西去学习收益很大,但是使用就不见得适合自己。

  • boost asio:has a “near STL” statusstackoverflow;

  • Poco: 很全面的库不仅仅有网络库。

  • libev :速度更快,bug更少,特性更多,体积更小;

  • libevent:简单,强大;

网络协议选则

网络编程中还有很重要的一点是客户端/服务端交互数据协议的选择。我们选择的依据有哪些呢?

  1. 网络数据大小——占用带宽,传输效率;

  2. 网络数据安全性——敏感数据的网络安全;

  3. 编码复杂度——序列化和反序列化复杂度,效率,数据结构的可扩展性,可 维护性;

  4. 协议通用性——大众规范;

  • 我们可以以自定义的角度采用TLV结构的二进制协议

  • 可以以提供序列化和反序列化库的的角度采用第三方协议:protocol buffers, json, thrift

  • 可以以选择文本化协议的角度选择xml,json协议。

我的理解是什么呢?请参见文章《网络传输数据格式的选择》

实践中你还常常会遇到

关键词MTU、SO_LINGER、TCPNODELAY、TIMEWAIT、keepalive、串话...这些关键词都代表了某种你需要考虑和处理的网络情况。

辅助工具python、netcat、tcpdump、wireshark...它们都会成为使你事半功倍的巨人。

推荐书籍:

《UNIX网络编程卷1》
《Linux多线程服务端编程》
《构建高性能Web站点》

参考资料

《UNIX网络编程卷1》
《Linux多线程服务端编程》
http://stackoverflow.com/questions/992069/ace-vs-boost-vs-pocohttp://stackoverflow.com/questions/9433864/whats-the-difference-between-libev-and-libevent

我的github项目

高性能tcp网络服务器

基于TCP协议的远程过程调用框架客户端实现

本文转自永远的朋友博客51CTO博客,原文链接http://blog.51cto.com/yaocoder/1556742如需转载请自行联系原作者


yaocoder


相关文章
|
14天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
14天前
|
程序员 开发者 Python
Python网络编程基础(Socket编程) 错误处理和异常处理的最佳实践
【4月更文挑战第11天】在网络编程中,错误处理和异常管理不仅是为了程序的健壮性,也是为了提供清晰的用户反馈以及优雅的故障恢复。在前面的章节中,我们讨论了如何使用`try-except`语句来处理网络错误。现在,我们将深入探讨错误处理和异常处理的最佳实践。
|
19天前
|
网络协议 程序员 Python
pythonTCP客户端编程创建Socket对象
【4月更文挑战第6天】本教程介绍了TCP客户端如何创建Socket对象。Socket作为网络通信的基础单元,包含协议、IP地址和端口等信息。在TCP/IP中,Socket分为流式(TCP)、数据报(UDP)和原始套接字。以Python为例,创建TCP Socket对象需调用`socket.socket(AF_INET, SOCK_STREAM)`。为确保健壮性,应使用异常处理处理可能的`socket.error`。学习本教程将帮助你掌握TCP客户端创建Socket对象的技能。
|
1月前
|
网络协议 Linux C语言
Linux实现socket网络通信
Linux实现socket网络通信
|
14天前
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
38 6
|
1天前
|
存储 网络协议 关系型数据库
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
|
13天前
|
网络协议 Java API
Python网络编程基础(Socket编程)Twisted框架简介
【4月更文挑战第12天】在网络编程的实践中,除了使用基本的Socket API之外,还有许多高级的网络编程库可以帮助我们更高效地构建复杂和健壮的网络应用。这些库通常提供了异步IO、事件驱动、协议实现等高级功能,使得开发者能够专注于业务逻辑的实现,而不用过多关注底层的网络细节。
|
17天前
|
Python
Python网络编程基础(Socket编程)UDP服务器编程
【4月更文挑战第8天】Python UDP服务器编程使用socket库创建UDP套接字,绑定到特定地址(如localhost:8000),通过`recvfrom`接收客户端数据报,显示数据长度、地址和内容。无连接的UDP协议使得服务器无法主动发送数据,通常需应用层实现请求-响应机制。当完成时,用`close`关闭套接字。
|
29天前
|
网络协议 Perl
Perl 教程 之 Perl Socket 编程 6
Perl Socket教程展示了如何进行网络通信。服务端(server.pl)创建一个TCP套接字,绑定到端口7890并监听,接收客户端连接并发送消息。客户端(client.pl)连接到服务端,接收并打印消息。在两个不同终端上分别运行服务端和客户端可实现交互。
24 2
|
30天前
|
网络协议 Perl
Perl 教程 之 Perl Socket 编程 1
Perl Socket教程介绍了如何进行服务端和客户端编程。服务端使用socket、bind、listen和accept函数建立并监听连接;客户端则通过socket和connect函数连接到服务端。socket函数创建套接字,参数包括协议集(如AF_INET)、套接字类型(如SOCK_STREAM)和传输协议(如TCP)。示例代码展示了如何在Perl中调用socket函数。
17 3