socket网络编程 的基本方法:--ongoing

本文介绍了网络编程的基本流程,从创建Server程序到处理客户端并发请求的不同模型,包括多线程/多进程、IO多路复用及结合使用的方式。并探讨了select系统调用的效率问题及其与epoll的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://blog.youkuaiyun.com/shuxiaogd/article/details/50366039
在学习网络编程时,我们总是从最简单的Server程序写起:

socket -> bind -> listen -> accept -> read -> write -> return

再接下来,就是学习如何处理客户端的并发请求。主要思路有:  

    使用多线程/多进程模型
    使用IO多路复用模型
    使用多线程 + IO多路复用模型

其中,使用IO多路复用模型,我们总是从select系统调用开始学起。但是,我们也总是听到,select效率太低了,大型项目中也从来不使用select/poll,而是使用的epoll。

那么,为什么select系统调用效率低下呢?而epoll又是作了哪方面改进,从而要高效很多呢?


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

其他随笔:

记忆起了select函数的用法:
专门开辟一个线程对串口发送过来的数据进行接受,但是这个线程并不是一直不停地运行的,没有数据过来时会被阻塞在select函数,从而不占用cpu的时间!!!
(这难道就是QSocketNotifier的 原理吗!!虽然其并没有单独开辟一个线程去执行槽函数!)
另一种方式阻塞: 打开串口时,设置为阻塞的方式!------------ 这种方式与select那种更好呢?::网友的说法:
 read()函数和write()函数本身就有阻塞的功能,那么为什么还要用select呢?个人觉得用select主要有以下两个原因
    1、select可以监控多个文件描述符的状态,等相应的描述符有变化了再去读写。这时如果不用select的话,每个描述符你都要开一个进程去等待,太浪费资源了。
    2、使用select可以进行非阻塞开发。如果不想在网络包还没来之前一直阻塞在recv(),这时候就可以设置select参数timeout的值来处理了。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
在Beginning linux progrmming的第637页,有关于iotcl的使用例子,可以整理一下。
ioctl 是用来设置硬件控制寄存器,或者读取硬件状态寄存器的数值之类的。而read,write 是把数据丢入缓冲区,硬件的驱动从缓冲区读取数据一个个发送或者把接收的数据送入缓冲区。


ioctl(keyFd, FIONREAD, &b)
ref :  https://blog.youkuaiyun.com/yasi_xi/article/details/8246446


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
在Beginning linux progrmming的第640页,是服务器端的代码,其用了一种判断一个已经连接的client是否还在的方法:
先用select函数,如果结果是该client是可读的,然后调用ioctl(keyFd, FIONREAD, &bytes),得到可以都的字节数是几个,如果是0(这种情况是不是对应调用recv返回-1),则直接关闭这个client!
(客户端也可以用这方法判断server是否alive吧!)

转载于:https://www.cnblogs.com/butterflybay/p/10347925.html

在Delphi中,套接字(Socket)编程用到的基本类是TServerSocket与TClientSocket。这两个类全部位于ScktComp单元中。其类型定义如下: type TServerSocket = class (ScktComp.TCustomServerSocket); TClientSocket = class (ScktComp.TCustomSocket)。      在编写程序时,首先要对TServerSocket(在服务器端)与TClientSocket(在客户端)进行实例化。对于TServerSocket的对象,主要设置其服务类型(ServerType)与端口(Port)的属性,然后编写“OnClientRead”事件处理程序的代码,处理来自客户机的请求。如要启动服务器,设置TServerSocket对象的Active属性为真(即Active := True),如要停止服务器,则设置TServerSocket对象的Active属性为假(即Active := False)。      对于TClientSocket的对象,主要设置对方服务器的服务类型(ServerType)、端口(Port)以及IP地址(Address)的属性,之后编写“OnConnect与OnRead”事件处理程序的代码“OnConnect”事件处理程序用来检查与服务器连接成功与否(必须在这里进行检查才有效),“OnRead”事件处理程序用来读取服务器发来的信息。如要连接服务器,设置TClientSocket对象的Active属性为真(即Active := True;注意:检查连接是否成功,必须在“OnConnect”事件处理程序中进行),如要断开与服务器的连接,则设置TClientSocket对象的Active属性为假(即Active := False)。
aotosar中/* ******************************************************************************* * Function Name: DoIP_IfTransmit * * Explanation: By calling this API with the corresponding DoIPPduRRxId the * currently ongoing data reception is terminated immediately. When * the function returns, no reception is in progress anymore with * the given DoIPPduRRxId identifier. * * param: PduIdType id: Identification of the I-PDU. * const PduInfoType* info: Length and pointer to the buffer of the I-PDU. * * retval: E_OK: Request is accepted by the destination module. * E_NOT_OK: Request is not accepted by the destination module. ******************************************************************************* */ FUNC(Std_ReturnType, DOIP_CODE) DoIP_IfTransmit ( PduIdType id, P2CONST(PduInfoType, AUTOMATIC, DOIP_APPL_CONST) info ) { /* polyspace +1 MISRA-C3:D4.5 [Justified:Unset] "NSCA_Polyspace_DoIP_Dir4.5" */ uint8 errorId = DOIP_E_NO_ERROR; Std_ReturnType retVal = E_NOT_OK; PduIdType connection; if( DOIP_STATE_INIT != DoIP_State ) { errorId = DOIP_E_UNINIT; } /* polyspace +1 DEFECT:DEAD_CODE [Justified:Unset] "NSCA_Polyspace_DoIP_Dead_Code" */ else if( (DOIP_CHANNELS_TOTAL <= id) || (DOIP_IFPDU != DoIP_Channel2ApiType[id]) ) { errorId = DOIP_E_INVALID_PDU_SDU_ID; } /* polyspace +2 MISRA-C3:2.1 [Justified:Unset] "NSCA_Polyspace_Common_Unreachable" */ /* polyspace +1 RTE:UNR [Justified:Unset] "NSCA_Polyspace_DoIP_UNR" */ else if( (NULL_PTR == info->SduDataPtr) || (info == NULL_PTR) ) { errorId = DOIP_E_PARAM_POINTER; } else if( (DOIP_ZERO != info->SduLength) || (DoIP_Channel2IfTxBuf[id].maxBufLen <= info->SduLength) ) { errorId = DOIP_E_INVALID_PARAMETER; } else { /* Check if previous transmission is pending. */ if( DOIP_ZERO == DoIP_Channel2TxMsgLen[id] ) { /* Get tester socket connection. */ connection = DoIP_Channel2TcpCon[id]; /* No transmission pending. */ if( DOIP_INV_PDU_ID != connection ) { /* Tester is connected. */ DoIP_Channel2TxMsgLen[id] = info->SduLength; retVal = DoIP_TcpTransmit(connection, DOIP_HDR_TYPE_DIAG_REQ, (uint16)id, DOIP_ZERO, info->SduLength, info->SduDataPtr, FALSE); } } } #if( DOIP_DEV_ERROR_DETECT == STD_ON ) DoIP_Det_ErrorReport(DOIP_API_ID_IF_TRANSMIT, errorId); #endif return retVal; }
最新发布
08-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值