网络(2):网络配置&socket编程相关的函数选项及异常处理

本文详细介绍了网络编程中网络配置的相关参数,包括UDP和TCP的缓冲区大小设置,以及socket函数的使用,如socket、bind、listen、connect、accept、send、recv等。同时,文章探讨了各种网络异常情况,如连接建立过程中的异常、通信过程中的异常处理,并总结了connect、recv、send函数的返回状态及其可能原因。通过对这些内容的掌握,可以帮助开发者更好地理解和处理网络编程中的异常情况。
摘要由CSDN通过智能技术生成

一.网络编程配置:

修改UDP接收发送缓冲区大小:

1、修订单个socket的缓冲区大小:通过setsockopt使用SO_RCVBUF来设置接收缓冲区,该参数在设置的时候不会与rmem_max进行对比校验,但是如果设置的大小超过rmem_max的话,则超过rmem_max的部分不会生效;

发包缓冲区与收包缓冲区一样,只不过参数名称不一样:SO_SNDBUF、wmem_max。
2、修订linux系统udp缓冲区大小:通过rmem_max来设置系统中udp缓存的上限,该值可通过如下方式查看:
root@ubuntu:/mnt/hgfs/vm-shared/socket# cat /proc/sys/net/core/rmem_max
通过如下方式进行修订:
root@ubuntu:/mnt/hgfs/vm-shared/socket# vi /etc/sysctl.conf
在文件/etc/sysctl.conf中新增如下信息:
rmem_max=MAX
需要注意的这里设置的rmem_max参数是整个系统的大小,不是单个socket的大小。
修订后的大小可以通过如下命令查看:
root@ubuntu:/mnt/hgfs/vm-shared/socket# sysctl -a | grep rmem_max
net.core.rmem_max = 131071

修改udp缓冲区的大小

cat /proc/sys/net/core/rmem_default               // 默认发送缓冲区

echo 65536 > /proc/sys/net/core/wmem_default       // 默认接收缓冲区

总结
要修订linux udp收包缓冲大小,需要上述两个地方同时修改。
只改第1点,缓冲区大小会受到rmem_max的限制。
只改第2点,一个socket只会预留63个报文的接收缓冲。

修改TCP接收发送缓冲区大小:
修改tcp接收/发送缓冲区最大值

echo 65536 > /proc/sys/net/core/rmem_max
echo 256960 > /proc/sys/net/core/wmem_max
修改tcp接收/发送缓冲区,一般是最大值的一半
echo "4096 32768 65536" > /proc/sys/net/ipv4/tcp_rmem    // 接收缓冲区
echo "4096 65536 256960" > /proc/sys/net/ipv4/tcp_wmem   // 发送缓冲区
修改网络设备接收队列
echo 500 > /proc/sys/net/core/netdev_max_backlog
重传次数
echo 5 > /proc/sys/net/ipv4/tcp_retries2

 

通过函数设置

setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen); 

tcp 或 udp 接收缓冲区最大可设置值的一半。

也就是说调用 setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen);  时rcv_size 如果超过 131071,那么


getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen); 去到的值就等于 131071 * 2 = 262142

 

tcp 或udp收发缓冲区最小值

tcp 或udp接收缓冲区的最小值为 256 bytes,由内核的宏决定;
tcp 或udp发送缓冲区的最小值为 2048 bytes,由内核的宏决

 

其他选项:
1. /proc/sys/net/ipv4/tcp_timestamps — 时间戳在TCP的包头增加12个字节 
2. /proc/sys/net/ipv4/tcp_sack — 有选择的应答 
3. /proc/sys/net/ipv4/tcp_window_scaling — 支持更大的TCP窗口. 

 

二.Socket 函数:

 

其在linux和windows环境下的头文件主要是:#include<sys/socket.h>#include<WinSock2.h>

1.  socket

  Int socket(int domain,int type, int protocol)

  返回值:非负描述符 – 成功,-1 - 出错

  其中:

  Family指明了协议族/域

 AF_INET(ipv4网络)

 AF_INET6(ipv6网络)

 AF_LOCAL(本地)等;

   type是套接口类型

     SOCK_STREAM (提供面向连接的稳定数据传输,即TCP协议)

     OOB: 在所有数据传送前必须使用connect()来建立连接状态。

     SOCK_DGRAM 使用不连续不可靠的数据包连接。

     SOCK_SEQPACKET: 提供连续可靠的数据包连接。

     SOCK_RAW 提供原始网络协议存取。

     SOCK_RDM: 提供可靠的数据包连接。

     SOCK_PACKET: 与网络驱动程序直接通信。

   protocol一般取为0。成功时,返回一个小的非负整数值,与文件描述符类似。

       对于windows环境下,在调用该函数之前需首先调用WSAStartup函数完成对Winsock服务的初始化,如

   #include<WinSock2.h>

   WSADATA wdata;

   if ( WSAStartup(MAKEWORD(2,2), &wdata) !=0 ){

     return INVALID_SOCKET;

    }

   后面即可调用socket函数,参数意义与linux环境一致。 

2.  bind

Int bind(int sockfd,const struct sockaddr* myaddr,socklen_t addrlen)

返回值:0 – 成功,-1 - 出错

       当socket函数返回一个描述符时,只是存在于其协议族的空间中,并没有分配一个具体的协议地址(这里指IPv4/IPv6和端口号的组合),bind函数可以将一组固定的地址绑定到sockfd上。

其中:

sockfd是socket函数返回的描述符;

myaddr指定了想要绑定的IP和端口号,均要使用网络字节序-即大端模式;

addrlen是前面struct sockaddr(与sockaddr_in等价)的长度。

   为了统一地址结构的表示方法,统一接口函数,使得不同的地址结构可以被bind()、connect()、recvfrom()、sendto()等函数调用。但一般的编程中并不直接对此数据结构进行操作,而使用另一个与之等价的数据结构sockaddr_in。

       通常服务器在启动的时候都会绑定一个众所周知的协议地址,用于提供服务,客户就可以通过它来接连服务器;而客户端可以指定IP或端口也可以都不指定,未分配则系统自动分配。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。

       Windows下的版本:

Int bind( IN SOCKET s, IN const struct sockaddr FAR * name, IN int namelen);

 

3.  listen

Int listen(int sockfd,int backlog)

返回值:0 – 成功,-1 - 出错

     为了接受连接,先用socket()创建一个套接口的描述字,然后用listen()创建套接口并为申请进入的连接建立一个后备日志,然后便可用accept()接受连接了。listen()仅适用于支持连接的套接口,如SOCK_STREAM类型的。套接口s处于一种“变动”模式,申请进入的连接请求被确认,并排队等待被接受。这个函数特别适用于同时有多个连接请求的服务器;如果当一个连接请求到来时,队列已满,那么客户将收到一个WSAECONNREFUSED错误。

当没有可用的描述字时,listen()函数仍试图正常地工作。它仍接受请求直至队列变空。当有可用描述字时,后续的一次listen()或accept()调用会将队列按照当前或最近的“后备日志”重新填充,如有可能的话,将恢复监听申请进入的连接请求

   内核维护两个队列 未完成链接队列(等待完成三次握手),已完成链接队列(链接已经建立); 两个队列之和数量不得超过backlog.

 

4.  connect

Int connect(int sockfd,conststruct sockaddr *addr, socklen_t addrlen)

返回值:0 – 成功,-1 - 出错

       通过此函数建立于TCP服务器的连接,实际是发起三次握手过程,仅在连接成功或失败后返回。参数sockfd是本地描述符,addr为服务器地址,addrlen是socket地址长度。

UDP的connect函数,结果与tcp调用不相同,没有三次握手过程。内核只是记录对方的ip和端口号,他们包含在传递给connect的套接口地址结构中,并立即返回给调用进程。

 

5.  accept

Int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)

返回值:非负描述符 – 成功,-1 - 出错

   本函数从s的等待连接队列中抽取第一个连接,创建一个与s同类的新的套接口并返回句柄。如果队列中无等待连接,且套接口为阻塞方式,则accept()阻塞调用进程直至新的连接出现。如果套接口为非阻塞方式且队列中无等待连接,则accept()返回一错误代码。已接受连接的套接口不能用于接受新的连接,原套接口仍保持开放

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值