关键词不能为空

当前您在: 主页 > 英语 >

谈一谈网络编程学习经验

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-02-28 13:59
tags:

-

2021年2月28日发(作者:nbe)


谈一谈网络编程学习经验



作者


:


陈硕



来源


:


博客园



发布时间


: 2011-07-05 16:07


阅读


: 1842




推荐


: 0


原文链接



[

< p>



]




本文谈一谈我在学习网络编程方面的一些个人经验。



网络编程



这个术语 的范围很广,


本文


指用


Sockets API


开发基于


TCP/IP


的网络应 用程序,


具体定义见



网络编程的各种 任务角




一节。



受限于本人的经历和经验,这篇文章的适应范围是:




·


x86-64 Linux


服务端网络编程,直接或间接使用



Sockets API



·



公司内网。不一定是局域网,但总 体位于公司防火墙之内,环境可控




本文可能不适合:




·


PC


客户端网络编程,程序运行在 客户的


PC


上,环境多变且不可控




·


Windows


网络编程




·



面向公网的服务程序




·



高性能网络服务器




本文分两个部分:




1.


网络编程的一些胡思乱想,谈谈我对这一领域的认识




2.


几本必看的书,基本上还是


W. Richard Stevents


那几本




另外,


本文没有特别说明时均暗指


TCP


协议,



连接





TCP


连接< /p>





服务端< /p>




“TCP


服 务







网络编程的一些胡思乱想



以下胡乱列出我对网络编程的一些想法,前后无关联。




网络编程是什么?



网络编程是什么?是熟练使用


Sockets API


吗?说实话,在实际项目里我只用过两次


Sockets API


,其他时候都是使用封装好的网络库。




第一次是


2005

< br>年在学校做一个羽毛球赛场计分系统:我用


C#


编写运 行在


PC


机上的软


件,负责比分的显示 ;再用


C#


写了运行在


PDA


上的计分界面,记分员拿着


PDA


记录比


分;这两部分程序通过



TCP

< p>
协议相互通信。这其实是个简单的分布式系统,体育馆有不止


一片场地,每 个场地都有一名拿


PDA


的记分员,每个场地都有两台显示比分 的


PC


机(显


示器是

< br>42


吋平板电视,放在场地的对角,这样两边看台的观众都能看到比分)。这两台


PC


机功能不完全一样,一台只负责显示当前比分,另一台还要 负责与


PDA


通信,并更新


数据库里的 比分信息。


此外,


还有一台


PC


机负责周期性地从数据库读出全部


7


片场地的 比


分,显示在体育馆墙上的大屏幕上。这台


PC


上还运行着一个程序,负责生成比分数据的静


态页面,通过

FTP


上传发布到某门户网站的体育频道。系统中还有一个录入赛程(参赛队,


运动员,出场顺序等)数据库的程序,运行在数据库服务器上。算下来整个系统有十来个程< /p>


序,运行在二十多台设备(


PC



PDA


)上,还要考虑可靠性。将来有机会把这个小系统仔

< p>
细讲一讲,挺有意思的。



这是我第一次写实际项目中的网络程序,当时写下来的感觉是像写命令行与用户交互的程

序:程序在命令行输出一句提示语,


等待客户输入一句话,然后处理客户输入,再输 出下一


句提示语,如此循环。只不过这里的


< br>客户



不是人,而是另一个程序。在建立好


TCP


连接


之后,双方的程序都是

< br>read/write


循环(为求简单,我用的是


blo cking


读写),直到有


一方断开连接。



第二次是


2010

< p>
年编写


muduo


网络库,


我再次拿起了


Sockets API


写了一个基于


Reactor


模式的


C++


网络库。写这个库的目的之一就是想让日常的网络编程从

Sockets API


的琐


碎细节中解脱出来,让程序员 专注于业务逻辑,把时间用在刀刃上。


Muduo


网络库的示 例


代码包含了几十个网络程序,这些示例程序都没有直接使用


S ockets API





在此之外,无论是实习还是工作,虽然我写的程序都会通过


TCP


协议与其他程序打交道,


但我没有直接使用过


Sockets API



对于


TCP


网络编程,


我认为核心是处理



三个半事件




见《


Muduo


网络编程示例之零:前言》中的


“TCP

网络编程本质论



。程序员的主要工作

是在事件处理函数中实现业务逻辑,而不是和


Sockets API


较劲。



这里还是没有说清楚



网络编程



是什么,请继续阅读后文



网络编程的 各种任务角色






学习网络编程有用吗?


< p>
以上说的是比较底层的网络编程,


程序代码直接面对从

TCP



UDP


收到的数据以及构 造数


据包发出去。在实际工作中,另一种常见



的情况是通过各种



client library


来与服务端打


交道,或者在现成的框架中填空 来实现


server


,或者采用更上层的通信方式。比如用


libmemcached



memcac hed


打交道,使用


libpq


来与< /p>


PostgreSQL


打交道,编写


S ervlet


来响应


http


请求,使 用某种


RPC


与其他进程通信,等等。这些情况都会发生网络< /p>


通信,但不一定算作



网络编程



。如果你的工作是前面列举的这些,学习


TC P/IP


网络编程


还有用吗?




我认为还是有必要学一学,


至少在< /p>


troubleshooting


的时候有用。


无论如何,


这些


library



framework


都会调用底层的


Sockets API


来实现网络功能。当你的程序遇到一个线上

< br>问题,如果你熟悉


Sockets API


,那么从


strace


不难发现程序卡在哪里,尽管可能你没有


直接调用这些


Sockets API


< p>
另外,


熟悉


TCP/IP


协议、


会用


tcpdump


也大大有助 于分析


解决线上网络服务问题。




在什么平台上学习网络编程?



对于服 务端网络编程,我建议在


Linux


上学习。

< br>



如果在


10


年前,这个问题的答案或许是


FreeBSD


,因为< /p>


FreeBSD


根正苗红,在


2000< /p>


年那一次互联网浪潮中扮演了重要角色,


是很多公司首选的免费服 务器操作系统。


2000



那会儿


Linux


还远未成熟,连


epoll


都还没有实现。(


FreeBSD



2001


年发布


4.1


版,


加入了


kqueue


,从此


C10k


不是问题。)




10


年后的今天,事情起了变化,< /p>


Linux


成为了市场份额最大的服务器操作系统


(/wiki/Usage_share_of_operating_systems)




Linux



种大众系统上学网络编程,


遇到什么问题会比较容易解决。


因为用的人多,


你遇到的问题别


人多半也遇到过;同 样因为用的人多,如果真的有什么内核


bug


,很快就会得到修 复,至


少有


work around


的 办法。如果用别的系统,可能一个问题发到论坛上半个月都不会有人


理。从内核源码的风 格看,


FreeBSD


更干净整洁,注释到位,但是无奈它的市 场份额远不



Linux


,学习


Linux


是更好的技术投资。




可移植性重要吗?



写网络程序要不要考虑移植性?这取决于项目需要,如果贵公司做的程序要卖给其他公司,


而对方可能使用


Windows


< br>Linux



FreeBSD



Solaris



AIX



HP-UX


等等操作系统,


这时候考虑移植性。


如果编写公司内部的服务器上用的网络程序,

那么大可只关注一个平台,


比如


Linux



因为编写和维护可移植的网络程序的代价相当高,


平 台间的差异可能远比想象


中大,


即便是


POSIX


系统之间也有不小的差异


(比如

Linux


没有


SO_NOSIGPIPE


选项)



错误的返回码也大不一样。

< br>



我就不打算把


muduo< /p>



Windows


或其他操作系统移植。


如果需要编写可移植的网络程序,


我宁愿用

libevent


或者


Java Netty


这样现成的库,把脏活累活留给别人。




网络编程的各种任务角色



计算机网络是个



big topic



涉及很多人物和角色,


既有开发人员 ,


也有运维人员。


比方说:


公司内部两 台机器之间



ping


不通,通常由 网络运维人员解决,看看是布线有问题还是路


由器设置不对;两台机器能


ping


通,但是程序连不上,经检查是本机防火墙设置有问题,


通常由系统管理员解决;


两台机器能连上,


但是丢包 很严重,


发现是网卡或者交换机的网口


故障,由硬件维修人员解 决;两台机器的程序能连上,但是偶尔发过去的请求得不到响应,


通常是程序

< p>
bug


,应该由开发人员解决。




本文主要关心开发人员这一角色。下面简单列出一些我能想到 的跟网络打交道的编程任务,


其中前三项是面向网络本身,后面几项是在计算机网络之上 构建信息系统。




1.


开发网络设备,编写防火墙、交换机、路由器的固件



firmware



2.


开发或移植网卡的驱动




3.


移植或维护


TCP/IP


协议栈(特别是在嵌入式系统上)




4.


开发或维护标准的网络协议程序,


HTTP



FTP



DNS



SMTP



POP3



NFS



5.


开发标准网络协议的



附加品




比如


HAProxy



squid



varnish



web load balancer



6.


开发标准或非标准网络服务的客户端库,比如


ZooKeeper

客户端库,


memcached



户端库




7.

开发与公司业务直接相关的网络服务程序,比如即时聊天软件的后台服务器,网游服务


器,金融交易系统,互联网企业用的分布式海量存储,微博发帖的内部广播通知,等等




8.


客户端程序中涉及网络的部分,比如邮件客户端中与



POP3



SMTP


通 信的部分,以及


网游的客户端程序中与服务器通信的部分




本文所指的



网络编程



专指第


7


项,即在


TCP/IP


协议之上开发业务软件。




面向业务的网络编程的特点



跟开发通 用的网络程序不同,开发面向公司业务的专用网络程序有其特点:




·



业务逻辑比较复杂,而且时常变化




如果写一个


HTTP


服务器,在大致实 现


HTTP /1.1


标准之后,程序的主体功能一般不会有< /p>


太大的变化,程序员会把时间放在性能调优和


bug


修复上。而开发针对公司业务的专用程


序时,功能说明书(

< br>spec


)很可能不如


HTTP/1.1


标准那么细致明确。更重要的是,程序


是快速演化的。


以即时聊天工具的后台服务器为例,


可能第一版只支持在线聊天;


几个月之


后发布第二版,支持离线消息;又过了几个月,第三版支持隐身聊天;随后, 第四版支持上


传头像;如此等等。这要求程序员能快速响应新的业务需求,公司才能保持 竞争力。




·



不一定需要遵循公认的通信协议标准




比方说网游服务器就没什么协议标准,


反正客户端和服务端都是 本公司开发,


如果发现目前


的协议设计有问题,两边一起改了就 是了。




·



程序结构没有定论




对于高并发大吞吐的标准网络服务,


一般采用单线程事件驱动的方式开发,


比如


HAProxy


lighttpd


等都是这个模式。但是对于专用的业务系统,其业务逻辑比较复杂 ,占用较多的


CPU


资源,这种单线程事件驱动方式不见得能发 挥现在多核处理器的优势。这留给程序员


比较大的自由发挥空间,做好了横扫千军,做烂 了一败涂地。




·



性能评判的标准不同




如果开发


httpd


这样的通用服务,


必然会和开源的


Nginx



lighttpd


等高性能服务器比较,


程序员要投入相当的 精力去优化程序,


才能在市场上占有一席之地。


而面向业务的专 用网络


程序不一定有开源的实现以供对比性能,程序员通常更加注重功能的稳定性与开发 的便捷


性。性能只要一代比一代强即可。




·



网络编程起到支撑作用,但不处于主导地位




程序员的主要工作是实现业务逻辑,


而不只是实现网络通信协议。


这要求程序员深入理解业


务。程序 的性能瓶颈不一定在网络上,瓶颈有可能是


CPU


< p>
Disk IO


、数据库等等,这时优


化网络方面 的代码并不能提高整体性能。


只有对所在的领域有深入的了解,


明白各种因素的


权衡


(trade- off)


,才能做出一些有针对性的优化。




几个术语



互联网上的很多口水战是由对同一术语的不同理解引起的,


比我写的

《多线程服务器的适用


场合》就曾经人被说是


< p>
挂羊头卖狗肉



,因为这篇文章中举的

< p>


master


例子


“< /p>


根本就算不上


是个网络服务器。因为它的瓶颈根本就跟网络无关。




·



网络服务器





网络服务器



这个术语确实含义模 糊,


到底指硬件还是软件?到底是服务于网络本身的机器


(交换 机、路由器、防火墙、


NAT


),还是利用网络为其他人或程序 提供服务的机器(打印


服务器、文件服务器、邮件服务器)。每个人根据自己熟悉的领域 ,可能会有不同的解读。


比方说或许有人认为只有支持高并发高吞吐的才算是网络服务器 。




为了避免无谓的争执,


我只用



网络服务程序



或者



网络应用程序



这种含义明确的术语。




发网络服务程序



通常不会造成误解。




·



客户端?服务端?





TCP


网络编程里边,客户端和服务端很容易区分, 主动发起连接的是客户端,被动接受


连接的是服务端。


当然,< /p>


这个



客户端



本身也可能是个后台服务程序,


HTTP Proxy



HTTP


Server


来说就是个客户端。




·



客户端编程?服务端编程?




但是



服务端编程





客户端编程



就不那么好区分。比如



Web crawler


,它会主动发起大


量连接,

扮演的是


HTTP


客户端的角色,


但似乎应该归入



服务端编程




又比如写一个



HTTP


proxy



它既会扮演服务端


——


被动接受


web browser


发起的连接,


也会扮演客户端


——


主动向



HTTP server


发起连接,它究竟算服务端还是客户 端?我猜大多数人会把它归入


服务端编程。




那么究竟如何定义



服务端编程






服务端编程需要处理大量并发连接?也许是,


也许不是。


比如云风在一篇介绍网游服务器的


博客


/2006/04/iocp_kqueue_


中就谈到,网


游中用到的



连接服务器


需要处理大量连接,




逻辑服务器



只有一个外部连接。

< p>
那么开发


这种网游



逻辑 服务器



算服务端编程还是客户端编程呢?



我认为,


< br>服务端网络编程



指的是编写没有用户界面的长期运行的 网络程序,


程序默默地运


行在一台服务器上,

< br>通过网络与其他程序打交道,


而不必和人打交道。


与之对 应的是客户端


网络程序,要么是短时间运行,比如


wget


;要么是有用户界面(无论是字符界面还是图形


界面)。本文主要谈 服务端网络编程。




7x24


重要吗?内存碎片可怕吗?



一谈到服务端网络编程,


有人立刻会提出


7x24


运行的要求。


对于某些网络设备而言,


这是


合理的需求,比如交换机、路由器。对于开发商业系统,


我认为要求程序


7x24


运行通常是

< br>系统设计上考虑不周。具体见《分布式系统的工程化开发方法》第


20

< p>
页起。重要的不是


7x24


,而是在程序不必做到


7x24


的情况下也能达到足够高的可用性。一个考虑周到的系


统应该允许每个进程都能随时重启,这样才能在廉价的服务器硬件上做到高可用性。




既然不要求


7 x24


,那么也不必害怕内存碎片,理由如下:




·


64-bit

< br>系统的地址空间足够大,不会出现没有足够的连续空间这种情况。




·



现在的 内存分配器



malloc


及其第三方 实现)


今非昔比,除了


memcached

这种纯以内


存为卖点的程序需要自己设计分配器之外,


其他 网络程序大可使用系统自带的


malloc


或者


某个第三方实现。




·


Linux Kernel


也大量 用到了动态内存分配。既然操作系统内核都不怕动态分配内存造成


碎片,应用程序为什么 要害怕?




·



内存碎片如何度量?有没有什么工 具能为当前进程的内存碎片状况评个分?如果不能比


较两种方案的内存碎片程度,谈何优 化?




有人为了避免内存碎片,不使 用


STL


容器,也不敢


new/del ete


,这算是


premature


optimization


还是因噎废食呢?




协议设计是网络编程的核心



对于专用的业务系统,


协议设计是核心任务,


决定了系统的开发难度与可靠性,


但是这个领


域还没有形成大家 公认的设计流程。




系统中哪个程序 发起连接,哪个程序接受连接?如果写标准的网络服务,那么这不是问题,


< p>
RFC


来就行了。自己设计业务系统,有没有章法可循?以网游为例,到底 是连接服务器


主动连接逻辑服务器,


还是逻辑服务器主动连接< /p>



连接服务器



?似乎没有定论,


两种做法都


行。一般可以按照



依赖


->


被依赖

< p>


的关系来设计发起连接的方向。




比新建连接难的是关闭连接。在传统的网络服务中

< p>
(特别是短连接服务),不少是服务端主


动关闭连接,比如


daytime



HTTP/1.0

< br>。也有少部分是客户端主动关闭连接,通常是些长


连接服务,比如



echo



chargen


等。我们自己的业务系统该如何设计连接关闭协议呢?




服务端主动关闭连接的缺点之一是会多占用服务器资源。服务 端主动关闭连接之后会进入


TIME_WAIT


状态,在一段时 间之内


hold


住一些内核资源。如果并发访问量很高,这会影


响服务端的处理能力。


这似乎暗示我们应该把协议设计为客户端 主动关闭,



TIME_WAIT


状态 分散到多台客户机器上,化整为零。




这又有另外的问题:


客户端赖着不走怎么办?会不会造成拒绝服务攻击?或许有一个二 者结


合的方案:客户端在收到响应之后就应该主动关闭,这样把



TIME_WAIT


留在客户端。服


务端有一个定时器,


如果客户端若干秒钟之内没有主动断开,


就 踢掉它。


这样善意的客户端


会把


TIM E_WAIT


留给自己,


buggy


的 客户端会把



TIME_WAIT


留给 服务端。或者干脆


使用长连接协议,这样避免频繁创建销毁连接。




比连接的建立与断开更重要的是设计消息协议。消息格式 很好办,


XML



JSON

< p>


Protobuf


都是很好的选择;

< p>
难的是消息内容。


一个消息应该包含哪些内容?多个程序相互通信如何避< /p>



race condition


(见《 分布式系统的工程化开发方法》


p.16


的例子)?系统的全局 状态


该如何跃迁?可惜这方面可供参考的例子不多,


也没有太多 通用的指导原则,


我知道的只有


30


年 前提出的


end-to-end principle



happens-before rel ationship


。只能从实践中


慢慢积累了。




网络编程的三个层次



侯捷先生在《漫談程序員與編程》中讲到



STL


运用的三个档次:



會用


STL


,是一種檔次。


STL


原理有所了解,又是一個檔次。追蹤過

< p>
STL


源碼,又是一個檔次。第三種檔次的人


用起



STL


來,虎虎生風之勢絕非第一檔次的人能夠望其項背。




我认为网络编程也可以分为三个层次:




1.


读过教程和文档




2.


熟悉本系统


TCP/IP


协议栈的脾气




3.


自己写过一个简单的


TCP/IP stack



第一个层次是基本要求,读过《


Un ix


网络编程》这样的编程教材,读过《


TCP/IP


详解》


基本理解


TCP/IP

< br>协议,


读过本系统的


manpage


这个层次可以编写一些基本的网络程序,


完成常见的任务 。但网络编程不是照猫画虎这么简单,若是按照


manpage


的功能描述就


能编写产品级的网络程序,那人生就太幸福了。




第二个层次,


熟悉本系统的


TCP/IP


协议栈参数设置与优化是开发高性能网络程序的必备条


件。摸透协议栈的脾气还能解决工作中遇到的比较复杂的网络问题。拿


Linux



TCP/IP


协议栈来 说:




·



有可能出现自连接(见《学之者生,用之者死


——


ACE


历史与简评》举的三个硬伤),


程序应该有所 准备。




·


Linux


的内核会有


bug


,比如某 种


TCP


拥塞控制算法曾经出现


TCP window clamping


(窗口箝位)


bug


,导致吞吐量暴跌,可以选用其他拥塞控制算法来绕开


(work around)


这个问题。




这些阴暗角落在


manpage


里没有描述, 要通过其他渠道了解。




编写可靠的网络程序的关键是熟悉各种场景下的


error c ode


(文件描述符用完了如何?本



ephemeral port


暂时用完,不能发起新连接怎么办?服务端新建并发连接 太快,


backlog


用完了,客户端


connect


会返回什么错误?),有的在


manpage< /p>


里有描述,有


的要通过实践或阅读源码获得。


-


-


-


-


-


-


-


-



本文更新与2021-02-28 13:59,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/681610.html

谈一谈网络编程学习经验的相关文章

  • 余华爱情经典语录,余华爱情句子

    余华的经典语录——余华《第七天》40、我不怕死,一点都不怕,只怕再也不能看见你——余华《第七天》4可是我再也没遇到一个像福贵这样令我难忘的人了,对自己的经历如此清楚,

    语文
  • 心情低落的图片压抑,心情低落的图片发朋友圈

    心情压抑的图片(心太累没人理解的说说带图片)1、有时候很想找个人倾诉一下,却又不知从何说起,最终是什么也不说,只想快点睡过去,告诉自己,明天就好了。有时候,突然会觉得

    语文
  • 经典古训100句图片大全,古训名言警句

    古代经典励志名言100句译:好的药物味苦但对治病有利;忠言劝诫的话听起来不顺耳却对人的行为有利。3良言一句三冬暖,恶语伤人六月寒。喷泉的高度不会超过它的源头;一个人的事

    语文
  • 关于青春奋斗的名人名言鲁迅,关于青年奋斗的名言鲁迅

    鲁迅名言名句大全励志1、世上本没有路,走的人多了自然便成了路。下面是我整理的鲁迅先生的名言名句大全,希望对你有所帮助!当生存时,还是将遭践踏,将遭删刈,直至于死亡而

    语文
  • 三国群英单机版手游礼包码,三国群英手机单机版攻略

    三国群英传7五神兽洞有什么用那是多一个武将技能。青龙飞升召唤出东方的守护兽,神兽之一的青龙。玄武怒流召唤出北方的守护兽,神兽之一的玄武。白虎傲啸召唤出西方的守护兽,

    语文
  • 不收费的情感挽回专家电话,情感挽回免费咨询

    免费的情感挽回机构(揭秘情感挽回机构骗局)1、牛牛(化名)向上海市公安局金山分局报案,称自己为了挽回与女友的感情,被一家名为“实花教育咨询”的情感咨询机构诈骗4万余元。

    语文