首页技术accept函数原型(accept函数后会不会新端口)

accept函数原型(accept函数后会不会新端口)

编程之家2026-06-09915次浏览

各位老铁们好,相信很多人对accept函数原型都不是特别的了解,因此呢,今天就来为大家分享下关于accept函数原型以及accept函数后会不会新端口的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!

accept函数原型(accept函数后会不会新端口)

函数的可变参数详谈

可变参数的英文表示为:variable argument.

它在函数的定义时,用三个点号'.'表示,用逗号与其它参数分隔.

可变参数的特点:不像固定参数那样一一对应,也不像固定参数有固定的参数类型和参数名称;可变参数中个数不

定可是传入的是一个参数也可以是多个;可变参数中的每个参数的类型可以不同,也可以相同;可变参数的每个参数并没有

实际的名称与之相对应.

由此可见,可变参数的形式非常自由而富有弹生.因些,它给那些天才程序员有更大地想象和发挥空间.

accept函数原型(accept函数后会不会新端口)

然而,更多地自由,同样也加大操作上的难度.

以下就对可变参数的几个方面作一定的介绍.

1)可变参数的存储形式.

大家都知道,一般函数的形参属于局部变量.而局部变量就是存储在内存的栈区(所谓的栈区:由编译器自动分配释放,

存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。).可变参数也是存储在内存栈区.

在对函数的形参存储的时侯,编译器是从函数的形参的右边到左边逐一地压栈,

accept函数原型(accept函数后会不会新端口)

这样保证了栈顶是函数的形参的第一个参数(从左到右数).而80x86平台下的内存分配顺序是从高地址内存到低地址内存.

因此,函数的形参在内存的存储形式如下图(以fun(int var1,int var2,...,int var3,int var4)为例):

栈区:

|栈顶低地址

|第一个固定参数var1

|可变参数前的第一个固定参数var2

|可变参数的第一个参数

|...

|可变参数的最后一个参数

|函数的倒数第二个固定参数var3

|函数的最后一个固定参数var4

|...

|函数的返回地址

|...

|栈底高地址

2)使用可变参数所用到头文件和相关宏说明

在此,以TC2.0编译器为参考对象来说明.

可变参数的相关定义在TC2.0的名为"STDARG.H"的头文件中.

此文件为:

/* stdarg.h

Definitions for ACCESSing parameters in functions that accept

a variable number of arguments.

Copyright(c) Borland International 1987,1988

All Rights Reserved.

*/

#if __STDC__

#define _Cdecl

#else

#define _Cdecl cdecl

#endif

#if!defined(__STDARG)

#define __STDARG

typedef void*va_list;

#define va_start(ap, parmN)(ap=...)

#define va_arg(ap, type)(*((type*)(ap))++)

#define va_end(ap)

#define _va_ptr(...)

#endif

以上为"STDARG.H"的内容.

该文件定义了使用可变参数所用到的数据类型:typedef void*va_list;

va_start(ap,parmN)起到初始化,使用得ap指向可变参数的第一个参数.ap的类型为va_list,

parmN为可变参数的前面一个固定参数.

va_arg(ap,type)获得当前ap所指向的参数,并使ap指向可变参数的下一个参数,type为需要获得的参数的类型.

va_end(ap)结束可变参数获取.

3)可变参数的使用实例

实例目的:用可变参数来实现个数不定的字符串的传递,并显示传递过来的字符串.

#include

#include

#include

void tVarArg(int num,...);/*num为可变参数的个数*/

int main(void)

{

clrscr();

tVarArg(5,"Hello!","My","name","is","neverTheSame.\n");

tVarArg(8,"This","is","an","example","about","variable-argument","in","funtion");

getch();

return 0;

}

void tVarArg(int num,...)

{

va_list argp;/*定义一个指向可变参数的变量*/

va_start(argp,num);/*初始化,使用argp指向可变参数的第一个参数*/

while(--num>=0)

printf("%s",(va_arg(argp,char*)));/*va_arg(argp,char*)获得argp所指向的参数,

并使用argp指向下一个参数,char*使用所获得的参数的类型转换为char*型.*/

va_end(argp);/*结束可变参数获取*/

return;

}

4)可变参数的使用需要注意的问题

1.每个函数的可变参数至多有一个.

2.va_start(ap,parmN)中parmN为可变参数前的一个固定参数.

3.可变参数的个数不确定,完全由程序约定.

4.可变参数的类型不确定,完全由va_arg(ap,type)中的type指定,然后就把参数的类型强制转换.

而printf()中不是实现了识别参数吗?那是因为函数

printf()是从固定参数format字符串来分析出参数的类型,再调用va_arg

的来获取可变参数的.也就是说,你想实现智能识别可变参数的话是要通

过在自己的程序里作判断来实现的.

5.编译器对可变参数的函数的原型检查不够严格,对编程人员要求很高.

socket是什么呀

套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。

一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口。

套接字是通信的基石,是支持TCP/IP协议的路通信的基本操作单元。

可以将套接字看作不同主机间的进程进行双间通信的端点,它构成了单个主机内及整个网络间的编程界面。套接字存在于通信域中,通信域是为了处理一般的线程通过套接字通信而引进的一种抽象概念。

套接字通常和同一个域中的套接字交换数据(数据交换也可能穿越域的界限,但这时一定要执行某种解释程序),各种进程使用这个相同的域互相之间用Internet协议簇来进行通信。

Socket(套接字)可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概念。它是网络环境中进程间通信的API(应用程序编程接口),也是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连进程。

通信时其中一个网络应用程序将要传输的一段信息写入它所在主机的 Socket中,该 Socket通过与网络接口卡(NIC)相连的传输介质将这段信息送到另外一台主机的 Socket中,使对方能够接收到这段信息。

Socket是由IP地址和端口结合的,提供向应用层进程传送数据包的机制。

类型

1、数据报套接字

无连接套接字,使用用户数据报协议(UDP)。在数据报套接字上发送或接收的每个数据包都单独寻址和路由。数据报套接字不能保证顺序和可靠性,因此从一台机器或进程发送到另一台机器或进程的多个数据包可能以任何顺序到达或可能根本不到达。在数据报套接字上发送广播可能需要特殊配置。

为了接收广播数据包,数据报套接字不应该绑定到特定地址,尽管在某些实现中,当数据报套接字绑定到特定地址时也可能接收广播数据包。

2、流套接字

面向连接的套接字,使用传输控制协议(TCP)、流控制传输协议(SCTP)或数据报拥塞控制协议(DCCP)。流套接字提供了无记录边界的有序且独特的无错误数据流,并具有用于创建和销毁连接以及报告错误的明确定义的机制。

流套接字以带外功能可靠地、有序地传输数据。在 Internet上,流套接字通常使用 TCP实现,以便应用程序可以使用 TCP/IP协议在任何网络上运行。

3、原始套接字

允许直接发送和接收 IP数据包,无需任何特定于协议的传输层格式。对于其他类型的套接字,根据选择的传输层协议(例如 TCP、UDP)自动封装有效载荷,并且套接字用户不知道与有效载荷一起广播的协议头的存在。从原始套接字读取时,通常包含标头。

从原始套接字传输数据包时,自动添加标头是可选的。

大多数套接字应用程序编程接口(API),例如基于Berkeley套接字的那些,支持原始套接字。Windows XP于 2001年发布,在Winsock接口中实现了原始套接字支持,但三年后,微软出于安全考虑限制了 Winsock的原始套接字支持。

原始套接字用于与安全相关的应用程序,如Nmap。原始套接字的一个用例是在用户空间中实现新的传输层协议。

原始套接字通常在网络设备中可用,用于路由协议,例如Internet组管理协议(IGMP)和开放最短路径优先(OSPF),以及用于Internet控制消息协议(ICMP)等事情,由ping实用程序。

以上内容参考百度百科-套接字

Socket编程的几种模式

其基本原理是:首先建立一个socket连接,然后对其进行操作,比如,从该socket读数据。因为网络传输是要一定的时间的,即使网络通畅的情况下,接受数据的操作也要花费时间。对于一个简单的单线程程序,接收数据的过程是无法处理其他操作的。比如一个窗口程序,当你接收数据时,点击按钮或关闭窗口操作都不会有效。它的缺点显而易见,一个线程你只能处理一个 socket,用来教课还行,实际使用效果就不行了。select模型为了处理多个socket连接,聪明的人们发明了select模型。该模型以集合来管理socket连接,每次去查询集合中的socket状态,从而达到处理多连接的能力,其函数原型是int select(int nfds, fd_set FAR* readfds, fd_set FAR* writefds, fd_set FAR* exceptfds, const struct timeval FAR* timeout)。比如我们判断某个socket是否有数据可读,我们首先将一个fdread集合置空,然后将socket加入到该集合,调用 select(0,&fdread,NULL,NULL,NULL),之后我们判断socket是否还在fdread中,如果还在,则说明有数据可读。数据的读取和阻塞模型相同,调用recv函数。但是每个集合容量都有一个限值,默认情况下是64个,当然你可以重新定义它的大小,但还是有一个最上限,自己设置也不能超过该值,一般情况下是1024。尽管select模型可以处理多连接,但集合的管理多少让人感到繁琐。异步选择模型熟悉windows操作系统的都知道,其窗口处理是基于消息的。人们又发明了一种新的网络模型——WSAAsyncSelect模型,即异步选择模型。该模型为每个socket绑定一个消息,当socket上出现事先设置的socket事件时,操作系统就会给应用程序发送这个消息,从而对该 socket事件进行处理,其函数原型是int WSAAsynSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent)。hWnd指明接收消息的句柄,wMsg指定消息ID,lEvent按位设置感兴趣的网络事件,入 WSAAsyncSelect(s,hwnd,WM_SOCKET, FD_CONNECT| FD_READ| FD_CLOSE)。该模型的优点是在系统开销不大的情况下同时处理许多连接,也不需要什么集合管理。缺点很明显,即使你的程序不需要窗口,也要专门为 WSAAsyncSelect模型定义一个窗口。另外,让单个窗口去处理成千上万的socket操作事件,很可能成为性能瓶颈。事件选择模型与WSAAsynSelect模型类似,人们还发明了WSAEventSelect模型,即事件选择模型。看名字就可以猜测出来,它是基于事件的。WSAAsynSelect模型在出现感兴趣的socket事件时,系统会发一个相应的消息。而WSAEventSelect模型在出现感兴趣的socket事件时,系统会将相应WSAEVENT事件设为传信。可能你现在对sokect事件和普通WSAEVENT事件还不是很清楚。 socket事件是与socket操作相关的一些事件,如FD_READ,FD_WRITE,FD_ACCEPT等。而WSAEVENT事件是传统的事件,该事件有两种状态,传信(signaled)和未传信(non-signaled)。所谓传信,就是事件发生了,未传信就是还没有发生。我们每次建立一个连接,都为其绑定一个事件,等到该连接变化时,事件就会变为传信状态。那么,谁去接受这个事件变化呢?我们通过一个 WSAWaitForMultipleEvents(...)函数来等待事件发生,传入参数中的事件数组中,只有有一个事件发生,该函数就会返回(也可以设置为所有事件发生才返回,在这里没用),返回值为事件的数组序号,这样我们就知道了哪个事件发生了,也就是该事件对应的socket有了socket操作事件。该模型比起WSAAsynSelect模型的优势很明显,不需要窗口。唯一缺点是,该模型每次只能等待64个事件,这一限制使得在处理多 socket时,有必要组织一个线程池,伸缩性不如后面要讲的重叠模型。重叠I/O(Overlapped I/O)模型重叠I/O(Overlapped I/O)模型使应用程序达到更佳的系统性能。重叠模型的基本设计原理是让应用程序使用重叠数据结构,一次投递一个或多个Winsock I/O请求。重叠模型到底是什么东西呢?可以与WSAEventSelect模型做类比(其实不恰当,后面再说),事件选择模型为每个socket连接绑定了一个事件,而重叠模型为每个socket连接绑定了一个重叠。当连接上发生socket事件时,对应的重叠就会被更新。其实重叠的高明之处在于,它在更新重叠的同时,还把网络数据传到了实现指定的缓存区中。我们知道,前面的网络模型都要用户自己通过recv函数来接受数据,这样就降低了效率。我们打个比方,WSAEventSelect模型就像邮局的包裹通知,用户收到通知后要自己去邮局取包裹。而重叠模型就像送货上门,邮递员发给你通知时,也把包裹放到了你事先指定的仓库中。重叠模型又分为事件通知和完成例程两种模式。在分析这两种模式之前,我们还是来看看重叠数据结构: typedef struct WSAOVERLAPPED{DWORD Internal; DWORD InternalHigh; DWORD Offset; DWORD OffsetHigh; WSAEVENT hEvent;}WSAOVERLAPPED, FAR* LPWSAOVERLAPPED;该数据结构中,Internal、InternalHigh、Offset、OffsetHigh都是系统使用的,用户不用去管,唯一关注的就是 hEvent。如果使用事件通知模式,那么hEvent就指向相应的事件句柄。如果是完成例程模式,hEvent设为NULL。我们现在来看事件通知模式,首先创建一个事件hEvent,并创建一个重叠结构AcceptOverlapped,并设置AcceptOverlapped.hEvent= hEvent,DataBuf是我们事先设置的数据缓存区。调用 WSARecv(AcceptSocket,&DataBuf,1,&RecvBytes,&Flags,&AcceptOverlapped,NULL),则将AcceptSocket与AcceptOverlapped重叠绑定在了一起。当接收到数据以后,hEvent就会设为传信,而数据就会放到 DataBuf中。我们再通过WSAWaitForMultipleEvents(...)接收到该事件通知。这里我们要注意,既然是基于事件通知的,那它就有一个事件处理上限,一般为64。完成例程和事件通知模式的区别在于,当相应的socket事件出现时,系统会调用用户事先指定的回调函数,而不是设置事件。其实就是将WSARecv的最后一个参数设为函数指针。该回调函数的原型如下: void CALLBACK CompletionROUTINE( DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);其中,cbTransferred表示传输的字节数,lpOverlapped是发生socket事件的重叠指针。我们调用 WSARecv(AcceptSocket,&DataBuf,1,&RecvBytes,&Flags,&AcceptOverlapped,WorkerRoutine)将AcceptSocket与WorkRoutine例程绑定。这里有一点小提示,当我们创建多个socket的连接时,最好把重叠与相应的数据缓存区用一个大的数据结构放到一块,这样,我们在例程中通过lpOverlapped指针就可以直接找到相应的数据缓存区。这里要注意,不能将多个重叠使用同一个数据缓存区,这样在多个重叠都在处理时,就会出现数据混乱。完成端口模型下面我们来介绍专门用于处理为数众多socket连接的网络模型——完成端口。因为需要做出大量的工作以便将socket添加到一个完成端口,而其他方法的初始化步骤则省事多了,所以对新手来说,完成端口模型好像过于复杂了。然而,一旦弄明白是怎么回事,就会发现步骤其实并非那么复杂。所谓完成端口,实际是Windows采用的一种I/O构造机制,除套接字句柄之外,还可以接受其他东西。使用这种模式之前,首先要创建一个I/O完成端口对象,该函数定义如下: HANDLE CreateIoCompletionPort( HANDLE FileHandle, HANDLE ExistingCompletionPort, DWORD CompletionKey, DWORD NumberOfConcurrentThreads);该函数用于两个截然不同的目的:1)用于创建一个完成端口对象。2)将一个句柄同完成端口关联到一起。通过参数NumberOfConcurrentThreads,我们可以指定同时运行的线程数。理想状态下,我们希望每个处理器各自负责一个线程的运行,为完成端口提供服务,避免过于频繁的线程任务切换。对于一个socket连接,我们通过 CreateIoCompletionPort((HANDLE)Accept,CompletionPort,(DWORD)PerHandleData,0)将Accept连接与CompletionPort完成端口绑定到一起,CompetionPort对应的那些线程不断通过GetQueuedCompletionStatus来查询与其关联的socket连接是否有I/O操作完成,如果有,则做相应的数据处理,然后通过WSARecv将该socket连接再次投递,继续工作。完成端口在性能和伸缩性方面表现都很好,相关联的socket连接数目没有限制。

如果你还想了解更多这方面的信息,记得收藏关注本站。

和平精英 三周年庆新玩法?和平精英2023春节活动大饼ai变声器下载(大饼ai变声怎么设置)