再论关于如何学习网络编程期末试题

Linux线程全解-Linux应用编程和网络编程第7部分视频课程
亲爱的(ID:),该课程版权归电子发烧友所有,请勿用作其他用途。
加入发烧友学院 让学习更简单
200W+小伙伴在线陪你一起学习,让你的职业生涯更精彩
扫一扫,手机上观看
现价:¥29.00
本课程讲解Linux中线程,首先使用多进程解决上个课程中提出的并发式读取按键和鼠标的任务,然后引出多线程并讲解多线程的优势,最后详细讲了多线程的同步技术。学习本课程的目的是学会在linux应用编程中使用多线程技术。
我将从这门课程中学到什么?
1、ARM体系结构与汇编指令、寄存器、地址映射等2、常见外设的编程实践,如定时器、蜂鸣器、LCD、中断按键处理等3、专门针对linux内核驱动方向定制的C语言高级课程4、链表、栈、队列等数据结构详细介绍与代码演示5、uboot的用法、源代码逐行分析理解、三星官方uboot版本的移植以及uboot官方版本的移植,让你完全彻底地彻底掌握uboot6、linux内核的移植和一步一步构建自己的rootfs实验,彻底学会在开发板上搭建自己的嵌入式linux平台。7、文件操作、高级IO、进程线程等详细介绍,让你对linux应用编程完全上手。8、网络通信基础讲解和socket编程接口实战,学会写自己的网络通信服务器和客户端。9、linux驱动体系从零开始逐步介绍,让你从原理到实战都能做下来,一步步的掌握linux下各种驱动的编写、调试、使用。10、手把手带做项目,给职场小白一次从头参与项目立项、分析、程序编写、调试、功能升级、完结等完整过程的机会。
受众群体是什么?
物联网、嵌入式、计算机、电子、自动化、通信等相关专业大学生,希望学到企业需要的知识和技能从而能够找到更好的工作的人。刚毕业参加工作,从事硬件、单片机、嵌入式相关开发工作,希望能够提升自我技能,在工作中脱颖而出的。现从事其他工作,看好嵌入式物联网行业发展,没有电子软件基础和相关工作经验,希望能够零基础入门系统学习的人从事网站开发、APP开发等纯软件编程工作,希望学到一些嵌入式的编程能力以横向拓展个人技能面,从而提升价值者。
供应链服务
版权所有 (C) 深圳华强聚丰电子科技有限公司再论Java Swing线程_Java教程_动态网站制作指南
再论Java Swing线程
来源:人气:5597
  不正确的Swing线程是运行缓慢、无响应和不稳定的Swing应用的主要原因之一。这是许多原因造成的,从开发人员对Swing单线程模型的误解,到保证正确的线程执行的困难。即使对Swing线程进行了很多努力,应用线程逻辑也是很难理解和维护的。本文阐述了如何在开发Swing应用中使用事件驱动编程,以大大简化开发、维护,并提供高灵活性。   背景  既然我们是要简化Swing应用的线程,首先让我们来看看Swing线程是怎么工作的,为什么它是必须的。Swing API是围绕单线程模型设计的。这意味着Swing必须总是通过同一个线程来修改和操纵。为什么采用单线程模型,这有很多原因,包括开发成本和同步Swing的复杂性--这都会造成一个迟钝的API。为了达到单线程模型,有一个专门的线程用于和Swing组件交互。这个线程就是大家熟知的Swing线程,AWT(有时也发音为“ought”)线程,或者事件分派线程。在本文的下面的部分,我选用Swing线程的叫法。既然Swing线程是和Swing组件进行交互的唯一的线程,它就被赋予了很多责任。所有的绘制和图形,鼠标事件,组件事件,按钮事件,和所有其它事件都发生在Swing线程。因为Swing线程的工作已经非常沉重了,当太多其它工作在Swing线程中进行处理时就会发生问题。会引起这个问题的最常见的位置是在非Swing处理的地方,像发生在一个事件监听器方法中,比如JButton的ActionListener,的查找。既然ActionListener的actionPerformed()方法自动在Swing线程中执行,那么,数据库查找也将在Swing线程中执行。这将占用了Swing的工作,阻止它处理它的其它任务--像绘制,响应鼠标移动,处理按钮事件,和应用的缩放。用户以为应用死掉了,但实际上并不是这样。在适当的线程中执行代码对确保系统正常地执行非常重要。   既然我们已经看到了在适当的线程中执行Swing应用的代码是多么重要,现在让我们如何实现这些线程。我们看看将代码放入和移出Swing线程的标准机制。在讲述过程中,我将突出几个和标准机制有关的问题和难点。正如我们看到的,大部分的问题都来自于企图在异步的Swing线程模型上实现同步的代码模型。从那儿,我们将看到如何修改我们的例子到事件驱动--移植整个方式到异步模型。  通用Swing线程解决方案  让我们以一个最常用的Swing线程错误开始。我们将企图使用标准的技术来修正这个问题。在这个过程中,我们将看到实现正确的Swing线程的复杂性和常见困难。并且,注重在修正这个Swing线程问题中,许多中间的例子也是不能工作的。在例子中,我在代码失败的地方以//broken开头标出。好了,现在,让我们进入我们的例子吧。  假设我们在执行图书查找。我们有一个简单的用户界面,包括一个查找文本域,一个查找按钮,和一个输出的文本区域。这个接口如图1所示。不要批评我的UI设计,这个确实很丑陋,我承认。图 1. 基本查询用户界面  用户输入书的标题,作者或者其它条件,然后显示一个结果的列表。下面的代码例子演示了按钮的ActionListener在同一个线程中调用lookup()方法。在这些例子中,我使用了thread.sleep()休眠5秒来作为一个占位的外部查找。线程休眠的结果等同于一个耗时5秒的同步的服务器调用。
ivate void searchButton_actionPerformed() {  outputTA.setText("Searching for: " + searchTF.getText());  //Broken!! Too mUCh work in the Swing  thread String[] results = lookup(searchTF.getText()); outputTA.setText("");  for (int i = 0; i & results. i++)  {  String result = results[i];  outputTA.setText(outputTA.getText() + '\n' + result);   }}  假如你运行这段代码(完整的代码可以在这儿下载),你会立即发现存在一些问题。图2显示了查找运行中的一个屏幕截图。图 2. 在Swing线程中进行查找  注重Go按钮看起来是被按下了。这是因为actionPerformed方法通知了按钮绘制为非按下外观,但是还没有返回。你也会发现要查找的字串“abcde”并没有出现在文本区域中。searchButton_actionPerformed的第1行代码将文本区域设置为要查找的字串。但是,注重Swing重画并不是立即执行的。而是把重画请求放置到Swing事件队列中等待Swing线程处理。但是这儿,我们因查找处理占用了Swing线程,所以,它还不能马上进行重画。  要修正这些问题,让我们把查找操作移入非Swing线程中。我们第一个想到的就是让整个方法在一个新的线程中执行。这样作的问题是Swing组件,本例中的文本区域,只能从Swing线程中进行编辑。下面是修改后的searchButton_actionPerformed方法:
private void searchButton_actionPerformed() { outputTA.setText("Searching for: " + searchTF.getText());  //the String[][] is used to allow
to // setting the results from an inner class  final String[][] results = new String[1][1];  new Thread() {  public void run()  {   results[0] = lookup(searchTF.getText());   }  }.start(); outputTA.setText(""); for (int i = 0; i & results[0]. i++)   {  String result = results[0][i];  outputTA.setText(outputTA.getText() + '\n' + result);   }}  这种方法有很多问题。注重final String[][] 。这是一个处理匿名内部类和作用域的不得已的替代。基本上,在匿名内部类中使用的,但在外部环绕类作用域中定义的任何变量都需要定义为final。你可以通过创建一个数组来持有变量解决这个问题。这样的话,你可以创建数组为final的,修改数组中的元素,而不是数组的引用自身。既然我们已经解决这个问题,让我们进入真正的问题所在吧。图3显示了这段代码运行时发生的情况:图 3. 在Swing线程外部进行查找  界面显示了一个null,因为显示代码在查找代码完成前被处理了。这是因为一旦新的线程启动了,代码块继续执行,而不是等待线程执行完毕。这是那些希奇的并发代码块中的一个,下面将把它编写到一个方法中使其能够真正执行。  在SwingUtilities类中有两个方法可以帮助我们解决这些问题:invokerLater()和invokeAndWait()。每一个方法都以一个Runnable作为参数,并在Swing线程中执行它。invokeAndWait()方法阻塞直到Runnnable执行完毕;invokeLater()异步地执行Runnable。invokeAndWait()一般不赞成使用,因为它可能导致严重的线程死锁,对你的应用造成严重的破坏。所以,让我们把它放置一边,使用invokeLater()方法。要修正最后一个变量变量scooping和执行顺序的问题,我们必须将文本区域的getText()和setText()方法调用移入一个Runnable,只有在查询结果返回后再执行它,并且在Swing线程中执行。我们可以这样作,创建一个匿名Runnable传递给invokeLater(),包括在新线程的Runnable后的文本区域操作。这保证了Swing代码不会在查找结束之前执行。下面是修正后的代码:
private void searchButton_actionPerformed(){ outputTA.setText("Searching for: " + searchTF.getText());  final String[][] results = new String[1][1]; new Thread() {  public void run()   { //get results.   results[0] = lookup(searchTF.getText())   // send runnable to the Swing thread   // the runnable is queued after the   // results are returned    SwingUtilities.invokeLater(     new Runnable()     {     public void run()      {      // Now we're in the Swing thread      outputTA.setText("");       for (int i = 0; i & results[0]. i++)      {       String result = results[0][i];       outputTA.setText( outputTA.getText() + '\n' + result);       }       }    }   );  } }.start();}  这可以工作,但是这样做令人非常头痛。我们不得不对通过匿名线程执行的顺序,我们还不得不处理困难的scooping问题。问题并不少见,并且,这只是一个非常简单的例子,我们已经碰到了作用域,变量传递,和执行顺序等一系列问题。相像一个更复杂的问题,包含了几层嵌套,共享的引用和指定的执行顺序。这种方法很快就失控了。
优质网站模板什么思想决定什么样行为;什么样行为决定什么样的习惯,什么样的习惯决定什么样性格,而什么性格决定什么样的命运。...
几种网络编程方式的比较
几种网络编程方式的比较
一、常见的四种网络编程方式
1.ISAPI编程
ISAPI(即Internet Server Application Program Interface),是微软提供的一套面向Internet 服务的API接口,它能实现CGI(Common Gateway Interface,公共网关接口)能提供的全部功能,并在此基础上进行了扩展,如提供了过滤器应用程序接口。ISAPI的工作原理和CGI大体上是相同的,都是通过交互式主页取得用户输入信息,然后交服务器后台处理。但是二者在实现机制上大相庭径。ISAPI与CGI最大的区别在于:在ISAPI下建立的应用程序是以动态连接库(Dynamic Link Lib,DLL)的形式存在;而CGI的应用程序一般都是可执行程序。ISAPI应用的工作流程与CGI也有一些不同。ISAPI应用的DLL不仅可以象CGI程序一样被用户请求激活,还可以被系统预先激活来监视用户输入;对于被用户激活的DLL,在处理完一个用户请求后不会马上消失,而是继续驻留在内存中等待处理别的用户输入,直到过了一段时间后一直没有用户输入。一个ISAPI的DLL,可以在被用户请求激活后长驻内存,等待用户的另一个请求,还可以在一个DLL里设置多个用户请求处理函数,此外,ISAPI的DLL应用程序和WWW服务器处于同一个进程中,效率要显著高于CGI。不过ISAPI的平台兼容性较差,目前只能用于微软自己的Windows 95和NT操作系统上,服务器平台也仅限于IIS(Internet Information Server)和MS personal web server以及NT workstation上的peer web server。ISAPI DLLs的调用方法和CGI一样:在客户端使用GET或POST方法。
MFC中支持ISAPI的类有:
ChttpServer
CHttpServerContext
CHttpFilter
CHttpFilterContext
CHtmlStream
2.CGI编程
CGI的工作原理介绍:CGI(Common Gateway Interface)是一个WEB服务器提供信息服务的标准接口,通过这样一个接口,WEB服务器能够执行程序,并将程序输出的信息返回给浏览器。因为在WEB网上的数据都是静态的,通过CGI程序能够动态的处理浏览者的请求,如保存用户输入的信息,根据用户信息返回相关的资料等等。当客户端发送一个CGI请求给WEB服务器后,WEB服务器将根据CGI程序的类型决定数据向CGI程序的传送方式,一般来讲是通过标准输入/输出流和环境变量来与CGI程序间传递数据。CGI的输入/输出方法:CGI程序通过标准输入(STDIN)和标准输出(STDOUT)来进行输入输出,STDIN和STDOUT是两个预先定义好的文件指针。你可以利用文件读写函数来对其进行操纵。
3.WinInet编程
Win32 Internet 扩展提供了对普通Internet协议的访问,这些协议包括:gopher, FTP,和 HTTP,使用WinInet可以编写出高水平的Internet客户端程序,而不必去了解winsock、TCP/IP和特定Internet协议的细节。WinInet为所有三种协议提供了统一的函数集,既Win32 API接口。如果底层协议改变(如从FTP到HTTP),利用统一的函数集,用最少的代码就可以完成改变。Visual C++ 有两种方式来使用WinInet。一种是直接调用Win32 Internet函数,另一种是使用WinInet类库。
MFC 提供了下列的类和全程函数来创建Internet客户端程序。CInternetSession (父类 CObject)CInternetConnection (父类 CObject)
CFtpConnection
CGopherConnection
CHttpConnectionCInternetFile(父类 CStdioFile)
CGopherFile
CHttpFileCFileFind(父类 CObject)
CFtpFileFind
CGopherFileFindCGopherLocator(父类 CObject)CInternetException(父类 CException)全程函数:AfxParseURLAfxGetInternetHandleTypeAfxThrowInternetException这些类和全程函数除CFileFind在AFX.H里声明之外,其余都在AFXINET.H文件里声明。
4.Winsock编程
Winsock接口为进程间通信提供了一种新的手段,它不但能用于同一机器中的进程之间通信,而且支持网络通信功能。Winsock已经被正式集成到了Windows系统中,同时包括了16位和32位的编程接口。而Winsock的开发工具也可以在Borland C++6.0、Visual C++6.0这些C++编译器中找到,主要由一个名为winsock.h的头文件和动态连接库winsock.dll或wsodk32.dll组成,这两种动态连接库分别用于Win16和Win32的应用程序。winsock.dll或wsodk32.dll中包含socket与WSASocket系列操作的函数。
二、这几种方式的区别:
1)ISAPI主要是开发基于浏览器客户端与服务器端程序。效率比CGI方式高,而且也扩展了CGI没有的一些功能。(基于TCP/IP模型中的应用层)
2)CGI主要是开发基于浏览器客户端与服务器端程序。(基于TCP/IP模型中的应用层)
3)WinInet主要是开发客户端程序。(基于TCP/IP模型中的应用层)
4)Winsock主要是基于socket来开发客户端与服务器端程序。(基于TCP/IP模型中的各层)要想开发低层协议的程序的话就要了解协议的报文格式。
再论关于如何学习网络编程
网络编程学习笔记一:Socket编程
网络编程是什么
C++网络编程
socket网络编程的一些基础知识
初学网络编程心得
网络编程学习小结
游戏网络编程(一)
C++网络编程方面的开源项目
没有更多推荐了,socket 什么情况下会使得send函数想发送的字节数,和实际发送的字节数不相同
[问题点数:40分,结帖人iorsafeqq22]
本版专家分:0
结帖率 100%
CSDN今日推荐
本版专家分:2617
本版专家分:8
本版专家分:1347
本版专家分:3754
本版专家分:60
本版专家分:1120
本版专家分:220
本版专家分:13019
本版专家分:13967
本版专家分:358050
2013年 荣获名人称号
2011年 总版技术专家分年内排行榜第三2010年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第五
2012年1月 总版技术专家分月排行榜第一
本版专家分:358050
2013年 荣获名人称号
2011年 总版技术专家分年内排行榜第三2010年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第五
2012年1月 总版技术专家分月排行榜第一
本版专家分:18
匿名用户不能发表回复!|
其他相关推荐网络字节顺序采用big endian排序方式。为了进行转换 bsd socket提供了转换的函数 有下面四个htons 把unsigned short类型从主机序转换到网络序htonl 把unsigned long类型从主机序转换到网络序ntohs 把unsigned short类型从网络序转换到主机序ntohl 把unsigned long类型从网络序转换到主机序在使用little endian的系统中 这些函数会把字节序进行转换。
网络模块内部不会启动新的线程, 它在程序的主线程中运行. 由于网络io通常不是性能的热点, 一个线程是可行的. 需要注意的是, 如果所有功能都在一个线程处理, 会有一些隐患(下文提到), 通常我们需要为网络层单起一个线程.
网络模块提供几个接口, 用来监听网络地址, 发起连接, 断开连接. 发送数据. 这些接口都是非阻塞的. 同时它们也是线程安全的, 可以用多个线程来调用这些接口.
网络模块提供一个消息泵, 弹出网络层的状态和收到的数据. 用户可以根据具体情境, 在主线程处理这些数据,
也可以用新的工作线程来处理.
使用 epoll 来做多路复用IO接口. epoll 使用默认的水平触发模式. 用 Epoll 类来封装 epoll 的操作.
一个 Epoll 对象只有一个数据成员, 就是 epoll fd. 它有这几个接口:
创建, 销毁, 删除fd
添加需要监控的 fd: 添加的同时监听这个 fd 的读事件.
修改某个 fd 需要监控的事件类型: 通常我们总是需要监听读事件, 读事件根据参数来判断是否需要监听.
获取事件信息: 返回一个事件数组, 每个数组成员是一个结构体, 结构体包含这样的信息: 哪个fd发生了读/写事件.
简单的 Socket
用一个Socket类来封装 socket fd. 每个连接对应一个 socket 对象.
socket 对象必然包含一个 fd. 由于我们要求非阻塞的写数据, 所以socket对象还拥有一个 WriteBuffer. 这是最简单的情况.
SocketManager
在实际中, 网络连接会频繁的建立或断开. 不停的实例化然后又销毁Socket对象, 显然是低效的.
一个改进的方法是将不需要的 socket 对象放到池中, 需要的时候, 从池中拿出来, 初始化内部数据后继续使用.
这个方法使 socket 对象的数量逐渐增加, 然后稳定在某个数量.
另一方法是一开始就静态实例化一个足够大的socket对象数组. 数组的大小可以很简单的估算出来. 我们通过浪费一些内存换来了稳定的结构.
我采用的是第二种方法.
SocketManager的实现很简单. 它提供一个接口来返回一个未被使用的socket.
需要注意的是, 这个接口必须是线程安全的.
改进的 Socket
为了支持 SocketManager, 简单的Socket类需要一些额外的信息.
id: 用来区分其它socket对象, 实际上它等于该对象在数组中的下标.
state: 是否被使用的状态, 实际上还有许多其它状态
用户数据: 用户可以在里面保存一些信息. 比如该连接属于哪个模块(服务).
Socket 的写缓存
这个缓存用来暂时记录需要发送的数据, 在 fd 可写时, 发送它们.
为了避免字符串拷贝的开销, 我们约定, 应用层负责为需要发送的数据分配内存, 网络层的缓存只保存传递过来的指针. 数据发送完成后, 网络层释放这块内存. 这是一个重要的设计.
缓存内部数据结构是一个先进先出的队列(链表实现). 每条数据对应一个节点.
每个节点记录三个数据: 数据地址, 数据长度, 原始数据地址
发送数据的流程是这样的:
应用层需要发送数据, socket id, buffer, size
网络层找到这个 socket, 如果它的写缓存是空的, 直接发送(非阻塞的).
如果数据全部发送完, 操作完成.
如果数据没有发送完, 或者缓存不是空的, 把 buffer, size, offset(可能一部分数据已经发送了)记录到缓存中.
网络层异步的, 在 fd 可写的时候, 发送头节点的的数据, 根据发送的大小, 维护偏移.
如果某个节点的数据都发送完了, 释放这个节点的 buffer. 然后删除这个节点.
Socket 的读缓存
skynet并没有为socket实现读缓存. 每当socket收到数据, 网络层的消息泵就把这些数据传递出去.
这是因为网络层不涉及逻辑, 它不知道如何解析数据. 正如发送数据时, 网络层只是发送一个内存块, 它不知道内存块里是什么数据, 这些数据又是如何组织.
让逻辑层来解析和处理数据, 是一种适用面更广的设计.
用管道来同步
根实际情境, 你可以让把服务器的所有任务都在一个线程里处理. 但是更多的时候, 为了减低耦合, 利用多CPU, 网络模块在一个独立的线程中运行.
而网络的使用者, 可能来自多个线程.
所以, 我们需要同步应用层对网络层的操作. 一个线程安全的消息队列可以很好的完成这个任务.
还有一个更简洁的办法, 那就是使用管道.
用管道来作为应用层和网络层的桥梁. 使用者向管道写入操作,
管道保证操作同步, 网络线程从管道读出操作并执行. 管道大大减少了代码的复杂度.
网络层的消息指令非常简短, 绝大多数指令只有十几个字节. 发送数据的指令传递的是数据指针, 非常短小.
管道保证, 一次往管道里写入4096字节以内的数据, 都是原子操作. 我们不用烦心考虑同步问题.
另一方面, 管道的缓存空间是64K. 由于网络层能快速的处理指令, 这个容量够用了.
考虑最坏的情况, 管道缓存满了, 那么写管道的操作会阻塞. 等到管道里的指令被处理, 腾出空间, 数据再被写入.
所以指令不会丢失.
考虑一种特殊情况: 写管道操作和网络线程是同一线程, 并且管道满了. 由于写操作被阻塞, 网络线程无法处理指令, 系统就陷入死锁.
所以, 应用层和网络层最好是属于不同的线程.
我用监听操作的逻辑流程来举例说明应用层和网络层是如何配合的.
以use开头的操作属于应用线程(代码可能在网络层), 用net开头的操作属于网络线程.
use. 调用Listen函数.
use. 创建socket fd, 绑定网络地址, 开始监听.
use. 将一个状态为free的Socket对象互斥的置为reserve.
use. 把一条监听指令写入管道, 指令参数包括 socket fd, Socket id.
use. Listen函数返回 Socket id.
net. 从管道中读出监听指令.
net. 根据 Socket id, 找到socket对象, 初始化它, 把它的状态置为plisten.
use. 调用Start函数, 传入 Listen函数返回的Socket id
use. 启动指令写入管道.
net. 从管道读出启动指令.
net. 找到Socket对象, 把socket fd 添加到 epoll. Socket状态置为listen.
net. 处理连接事件.
Socket 的状态
socket的初始状态时free, 表明它未被使用.
如果要使用socket, 状态从 free 变为 reserve, 表明它已经被预定了, 做什么还不知道.
如果要用某个socket来监听, 状态从
reserve 变为 plisten, 此时它没有被添加到epoll .
系统初始化完成后, 网络启动, socket fd 添加到 epoll, 状态从 plisten 变为 listen. 它可以处理连接请求了.
如果有连接请求, 把 一个socket 的状态从 free 变为 reserve, 再变为 paccept, 此时它没有被添加到epoll
如果应用层决定接受这个连接, 把 socket fd 添加到 epoll, 状态从 paccept 变为 connected. 它可以发送和接收数据了.
如果要用某个socket来发起连接. 把 一个socket 的状态从 free 变为 reserve, 发起连接并把fd 添加进epoll.
状态是 connecting, 连接成功后(三次握手完成), 状态变为 connected. 它可以发送和接收数据了.
如果要关闭一个socket, 缓存里有数据, 状态先设为 halfclose, 数据发送完后, 设为 free.
状态时 halfclose的socket不会再读数据, 但是会继续把缓存的数据发送完.
好像水泵从水池里抽水一样, 应用层循环调用MsgLoop函数, 从网络层提取信息.
如果循环代码在一个独立的线程里执行, 这个线程就是网络线程.
消息泵会抛出这些消息:
data: socket 收到数据, 返回数据指针和长度, 应用层使用完后要释放指针指向的内存.
close: 连接关闭
open: 开始监听或连接建立.
accept: 有连接请求.
exit: 网络层退出.
发起连接时, 我们将socket设置为非阻塞的, 再调用 connect方法, 此时会立即返回一个错误码.
如果错误码是 EINPROGRESS, 说明连接正在进行(三次握手). 我们把 fd 添加到 epoll 中. 当连接完成的时候, epoll
会发出一个事件.
如果是其它错误码, 说明连接失败了. 终止连接操作.
往管道读写数据的时候, 如果返回 EINTR,
说明操作被系统中断, 需要重新写.
如果是其它错误, 打印一条错误日志.
往socket写数据的时候, 如果返回 EINTR(被中断),
可以马上重写,
如果返回 EAGAIN(被阻塞),
过一会再写.
如果是其它错误, 打印一条错误日志, 然后断开连接.
往socket读数据的时候, 如果返回 EINTR(被中断), 重新读,
如果返回 EAGAIN(被阻塞), 打印一条错误日志, 重新读.
如果是其它错误, 断开连接.
这些常量可以根据具体情境进行调整.
创建epoll的时候, 要告诉内核监听的数目有多大, 对应的 EPOLL_FD_MAX = 1024;
socket 监听网络地址时, 需要指定半连接队列的大小, 对应的 LISTEN_BACKLOG = 32;
从socket fd 读数据时, 由于我们事先不知道会读出多少数据, 在动态申请内存时, 一开始申请的大小是一个常量: MIN_READ_BUFFER
= 64; 每个socket的read_buffer_size是独立的, 而且会根据前一条数据的大小来动态调整: 增大一倍或缩小一倍.
由于Socket对象是被静态初始化的, 它们的数量要大于 EPOLL_FD_MAX , 而且我们希望可以快速的找到一个 free状态的socket对象. 所以它们的数量很多: MAX_SOCKET
网络编程是什么
C++网络编程
socket网络编程的一些基础知识
几种网络编程方式的比较
初学网络编程心得
网络编程学习笔记一:Socket编程
网络编程学习小结
游戏网络编程(一)
再论关于如何学习网络编程
C++网络编程方面的开源项目
没有更多推荐了,}

我要回帖

更多关于 网络编程学校 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信