博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
TCP 套接字函数
阅读量:5845 次
发布时间:2019-06-18

本文共 2611 字,大约阅读时间需要 8 分钟。

TCP(Transmission Control Protocol)为应用程序提供可靠的数据传输服务,它是网络编程中使用最广泛的一种(传输层)协议。

使用TCP通信的两个应用程序,一个作为服务器,另一个作为客户端。

下图是设计TCP程序的基本流程。

 

服务器端会有两个socket(并发服务器会有多个),其中一个是侦听socket(图中srv),等待客户来建立连接。另一个是接收到客户端连接请求而建立的新的socket,用于与客户端交互(图中clt)。

服务器启动时首先创建侦听socket srv,绑定本地地址,并在srv上侦听,调用accept后阻塞,直到有客户建立连接。accept返回一个新的socket clt,与客户端之间的交互全部通过clt完成。

当有一方关闭了连接,clt的任务完成,需要closesocket释放占用的资源。socket srv可以继续为其他的客户提供服务,通常不会关闭。

客户端先创建一个socket,调用connect与服务器建立连接。在connect的参数中指明要连接的服务器地址和端口,调用connect会导致TCP协议的三次握手。connect返回之后,三次握手完成,双方可以通过send和recv进行通信。

connect

int connect( SOCKET s,  const struct sockaddr FAR* name,  int namelen);

connect函数用于建立客户端与服务器端的连接。客户端调用connect发起主动连接,TCP协议开始三次握手过程,三次握手完成,connect返回成功,双方就可以在这个连接上交换数据了。

参数s是建立连接的socket句柄,name包含服务器地址和端口号。此函数成功返回0,失败返回SOCKET_ERROR,可以调用WSAGetLastError()获取具体错误码。如果错误码为WSAETIMEDOUT,代表超时。客户端连续发送SYN,但一直收不到服务器的确认ACK。标准实现的超时时间是75秒。

如果是阻塞socket,返回值立即指明了connect的成功或者失败。对于非阻塞socket,如果连接不能立即完成,connect返回SOCKET_ERROR,错误码为WSAEWOULDBLOCK,应用程序可以通过下面的情况来判断什么时候连接成功:(1)通过select函数,如果连接成功,socket将是可写的;(2)如果应用程序使用了WSAAsyncSelect,并且指明对连接事件感兴趣,当连接完成时会收到FD_CONNECT通知。

listen

int listen(SOCKET s, int backlog);

listen函数由服务器端使用,告诉系统在这个socket上接受连接请求。参数backlog称为“待处理连接的最大数目”,设置为SOMAXCONN,底层协议会把backlog设置为一个最大的“合理”值。

此函数成功返回0,失败返回SOCKET_ERROR,可以调用WSAGetLastError()获取具体错误码。

accept

SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen);

accept函数用于接受客户端连接请求,仅由服务器端使用,紧跟在listen调用之后。如果连接队列为空,默认阻塞调用线程。

参数s是侦听socket,addr用于接收连接客户端的地址,addrlen在传入时是缓冲区addr的长度,返回后包含了地址addr的实际长度。

accept成功将返回一个已连接socket,与客户端之间的交互全部通过该socket完成。失败则返回INVALID_SOCKET。

服务器端函数accept与客户端connect相对应。客户端调用connect时,向服务器发送SYN,服务器收到SYN,为进入的连接创建新的socket,把它添加到未完成连接队列中,向客户端发送SYN+ACK。客户端收到SYN和ACK,向服务器发送ACK,connect函数返回,表明成功建立连接。ACK一旦到达服务器就完成了三次握手,服务器把未完成连接转移到已完成连接队列中,socket的状态也从SYN_RCVD转变到ESTABLISHED,并唤醒服务线程,accept返回。

send

int send( SOCKET s,  const char FAR* buf,  int len,  int flags);

函数send在一个已连接的socket上向对方发送数据,对于tcp协议,发送的数据量大小没有限制。send成功返回发送数据的长度,可能小于参数len的长度,失败返回SOCKET_ERROR,可以调用WSAGetLastError()获取具体错误码。

参数s是已连接的socket,buf包含要发送的数据,len是buf中数据的长度,参数flags影响send函数的行为。flags可以设置为0,或者是MSG_DONTROUTE(不检查路由表,目的主机在直接相连的网络上),或者是MSG_OOB(发送带外数据),或者是它们的组合。

recv

int recv( SOCKET s,  char FAR* buf,  int len,  int flags);

recv从已连接套接字s接收数据。buf是用于接收数据的缓冲区,len是buf的长度。flags可以设置为0,或者是MSG_PEEK(查看是否有输入的数据可以读取,如果有数据会被复制到recv提供的缓冲区,但并不把数据从输入队列中删除),或者是MSG_OOB(接收带外数据),或者是它们的组合。

当套接字s上没有数据时,默认recv会阻塞调用线程,等待数据到达。非阻塞时,返回SOCKET_ERROR,错误码为WSAEWOULDBLOCK,程序可以调用select或者WSAAsyncSelect来确定什么时候有数据到达。

recv调用成功时,返回接收的字节数。当返回0时,对于面向连接的socket,表示对方正常关闭了这个连接。发生错误时,返回SOCKET_ERROR,可以调用WSAGetLastError()获取具体错误码。

转载于:https://www.cnblogs.com/zhuyf87/archive/2013/01/13/2858801.html

你可能感兴趣的文章
C语言获取系统时间的几种方式 原文出自【比特网】,转载请保留原文链接:...
查看>>
烂泥:拍拍店铺收藏代码
查看>>
【Java编程思想】操作符
查看>>
使用apache 提供的httpclient方式向服务器提交数据
查看>>
游侠观点:绿盾审计与加密产品分析
查看>>
利用Acunetix WVS发动批量网站漏洞评估
查看>>
windows下远程访问连接方式
查看>>
Centos7 安装mongoDB
查看>>
iscsi网络存储
查看>>
Nginx的软件升级
查看>>
自制一个 elasticsearch-spring-boot-starter
查看>>
Java构建CRM客户管理系统
查看>>
socket 简单的模板
查看>>
多台linux日志记录统一推送到一台linux服务器上面
查看>>
技术只是工具 做SEO要懂得和部门进行协调
查看>>
在window下与linux虚拟机建立共享文件夹
查看>>
我的友情链接
查看>>
以前一直去琢磨多种反射方式,一直找不到较好的资料
查看>>
java zip打包与乱码的解决
查看>>
PowerDNS不完全配置
查看>>