socker的基础知识(二)

套接字或者插座也是一种软件形式的抽象 ,用于表达两台机器之间连接的终端,

对于一个特定的连接,每台机器上都有一个套接字,可以想象它们之间有一条虚拟的线缆,线缆的每一端都插入一个套接字或者插座里。

应用层通过传输层进行数据通信时,TCPUDP会遇到同时为多个应用程序提供并发服务的问题,多个TCP连接或者多个应用程序进程可能 需要通过同一个TCP协议端口传输数据,为了区别不同的应用进程和连接,许多计算机系统为应用程序与TCP/IP协议交互提供了套接字的接口,区分不同应用程序进程间的网络通信和连接。

 

生成套接字:

通信的目的IP地址,使用的传输层协议(TCP/UDP)和使用的端口号,

将这三个参数结合起来,与一个插座绑定,应用层就可以和传输层通过套接字接口 ,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务

要通过互联网进行通信,至少需要一对套接字,一个运行于客户端,另一个运行于服务器。

步骤:

1.服务器监听:是服务器端套接字,并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。

2.客户端请求:指客户端套接字提出连接请求,要连接的目标是服务器套接字,为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

3.连接确认:服务器端监听或者接收到客户端套接字的连接请求,就响应客户端套接字的

请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了,而服务器端套接字继续处于监听状态,继续接收其他客户端套结字的连接请求。

 

 

 

TCP(面向连接编程)

socker的基础知识(二)_第1张图片

2.无连接编程(UDP

socker的基础知识(二)_第2张图片



Linux getsockopt /setsockopt 函数说明

通过调整套接字属性,能够实现广播,组播,地址重用,数据缓冲区以及数据超时处理等功能

 

 

功能:获取或者设置某个套接字关联的选项,选项可能存在于多层协议中,它们总是会出现在最上面的套接字层,当操作套接字选项时,选项位于的层和选项的名称必须给出,

#include           /* See NOTES */

       #include 

 

       int getsockopt(int sockfd, int level, int optname,

                      void *optval, socklen_t *optlen);

       int setsockopt(int sockfd, int level, int optname,

                      const void *optval, socklen_t optlen);

 

 

第一个参数:用于指定要操作的套接字

第二个参数:选项所在的协议层

第三个参数 :需要访问的选项名

第四个参数:对于getsockopt(),指向返回选项值的缓冲,对于setsockopt(),指向包含新选项的缓冲。

第五个参数:对于getsockopt(),作为入口参数时,选项值的最大长度,作为出口参数时,选项的实际长度,对于setsockopt(),现选项的长度

 成功返回0,失败返回-1errno被设置为下列值:

EBADF  :socket 不是有效的文件描述符

EFAULT  optval指向的内存并非有效的进程空间

EINVALoptlen  无效

ENOPROTOOPT:指定的协议层不能识别

 

ENOTSOCKsock描述的不是套接字

 

 

参数说明:

Level 指定控制套接字的层次:

1)SOL_SOCKET  :通用套接字选项

2)IPPROTO_IP  :IP选项

3)IPPROTP_TCP :TCP选项

 

Optname 指定控制的方式

Optval 获得或者是设置套接字选项。

 

选项名称        说明                  数据类型
========================================================================
SOL_SOCKET
------------------------------------------------------------------------
SO_BROADCAST      允许发送广播数据            int
SO_DEBUG        允许调试                int
SO_DONTROUTE      不查找路由int
SO_ERROR        获得套接字错误             int
SO_KEEPALIVE      保持连接                int
SO_LINGER 延迟关闭连接              struct linger
SO_OOBINLINE      带外数据放入正常数据流         int
SO_RCVBUF 接收缓冲区大小             int
SO_SNDBUF 发送缓冲区大小             int
SO_RCVLOWAT 接收缓冲区下限             int
SO_SNDLOWAT 发送缓冲区下限             int
SO_RCVTIMEO 接收超时                struct timeval
SO_SNDTIMEO 发送超时                struct timeval
SO_REUSERADDR 允许重用本地地址和端口         int
SO_TYPE 获得套接字类型             int
SO_BSDCOMPAT      与BSD系统兼容              int
========================================================================
IPPROTO_IP
------------------------------------------------------------------------
IP_HDRINCL       在数据包中包含IP首部          int
IP_OPTINOSIP首部选项               int
IP_TOS服务类型
IP_TTL         生存时间                int
========================================================================
IPPRO_TCP
------------------------------------------------------------------------
TCP_MAXSEGTCP最大数据段的大小           int
TCP_NODELAY 不使用Nagle算法             int
========================================================================

 

 

SO_RECVBUF  SO_SNDBUF每个套接口都有一个发送缓冲区和接收缓冲区,使用这两个套接口的选项可以改变缺省缓冲区的大小,

// 接收缓冲区
int nRecvBuf=32*1024; //设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));


//发送缓冲区
int nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

当设置TCP套接口缓冲区的大小时,函数调用顺序很重要,因为TCP 的窗口规模选项是建立在连接时用SYN与对方互换得到的,对于客户,O_RECVBUF 选项必须在connect 之前设置, 对于服务器,SO_RECVBUF 选项必须在listen 前设置

原理:

每个套接口都有一个发送缓冲区和一个接收缓冲区,接收缓冲区被TCPUDP用来接收到的数据一直保存到由应用进程来读,

TCP

TCP套接口接收缓冲区不可能溢出,因为对方不允许发出超过所通告窗口大小的数据,这就是TCP 的流量控制 ,如果对方无视窗口大小而发出超过窗口大小的数据,则接收方TCP将会丢弃它。

UDP

当接收到的数据装不进套接口的接收缓冲区时,此数据报就会被丢弃,UDP是没有流量控制的,快的发送者可以很容易的淹没慢的接收者,导致接收方的UDP丢弃数据报

Setsockopt 的用法:

(1)closesocket (一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket

BOOL Reuseaddr = TRUE;

Setsockopt(s,SOL_SOCKET, SO_REUSEADDR, (const char*)&Reuseaddr, sizeof(BOOL));

 

(2如果要已经处于连接状态的socket在调用closesocket后强制关闭,不经历TIME_WAIT 的过程

BOOL bDontLiner = FALSE;

Setsockopt(s, SOL_SOCKET, SO_DONTLINER, (const char*)&bDontLiner, sizeof(BOOL));

 

(3)send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限

Int  nNetTime = 1000

Setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&nNetTime, sizeof(int));设置发送时限

Setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nNetTime, sizeof(int));设置接收时限

(4)send()的时候,返回的是实际上发出去的字节(同步)或者发送到socket缓冲区的字节(异步);系统默认的状态发送和接收一次为8688字节,在实际的发送过程中发送数据和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发。

//接收缓冲区

Int nRecvBuf = 32*1024;

Setsockopt(s, SOL_SOCKET, SO_RECVBUF, (char*)&nRecvBuf, sizeof(int));

//发送缓冲区

Int nsendBuf = 32*1024

Setsockopt(s, SOL_SOCKET, SO_SNEBUF, (char*)&nsendBuf, sizeof(int));

(5)如果在发送数据时,不希望经历从系统缓冲区到socket 缓冲区的拷贝而影响程序的性能时

Int nZero = 0;

Setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char*)&nZero, sizeof(nZero));

(6)recv()上完成上述功能(默认是从socket缓冲区的内容拷贝到系统缓冲区)

Int nZero = 0;

Setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&nZero, sizeof(nZero));

(7)一般在发送UDP数据报时,希望该socket发送的数据具有广播特性

BOOL bBroadcast = TRUE;

Setsockopt(s, SOL_SOCKET, SO_BROADCAST, (const char*)&bBroadcast, sizeof(BOOL));

(8)client连接服务器过程中,如果处于非阻塞模式下socketconnect()过程中可以设置connect()延时,直到accept()被呼叫

该函数的设置只有在非阻塞的过程中有显著的作用,对于阻塞函数的作用不大

BOOL bConditionalAccept = TRUE;

Setsockopt(s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, (const char *)&bConditionalAccept, sizeof(BOOL));

(9)如果在发送数据的过程中send()没有完成,还有数据没发送,而调用了closesocket(),怎样设置让没发送完成的数据发送出去,然后再关闭socket?

Struct linger

{

u_short l_onoff;

u_short l_linger;

};

linger m_sLinger;

m_sLinger.l_onoff = 1;(closesocket()调用,但是还有数据没发送完毕的时候容许逗留)

如果m_sLinger.l_onoff = 0;则功能和(2)相同

m_sLinger.l_linger = 5;(容许逗留的时间为5)

Setsockopt(s, SOL_SOCKET, SO_LINGER, (const char*)&m_sLinger, sizeof(linger));

原始套接字:

原始套接字是一种套接字的底层技术,它工作在网络层,原始套接字可已完成以下功能:

1.设置网卡为混杂模式,嗅探当前网络 流经本网卡所得数据包

2.构造各种数据包(IP, ICMP, TCP, UDP),并进行发送

3.进行新协议的验证

原始套接字的创建:

Int rawsock = socket(AF_INET, SOCK_RAW, htons(ETH_P_TP));

协议码       协议名

IPPROTO    ICMP 协议

ETH_P_IP    IP协议

IPPROTO_TCP  TCP 协议

IPPROTO_UDP    UDP 协议


 



你可能感兴趣的:(书籍笔记)