linux socket msg oob,Linux Socket

0x0000 Linux Socket 函数

bind

listen

connect

accept

send

recv

read

write

0x0001

Server绑不上ip

报错位置在bind函数

[root@localhost 01]# ./server 191.168.80.151 1588

191.168.80.151 : 1588

Bind: Cannot assign requested address

port已被占用

报错位置在bind函数

[root@localhost 01]# ./server 192.168.80.151 1588

192.168.80.151 : 1588

Bind: Address already in use

没有这个网卡/端口号出不去

报错

Connect: No route to host

考虑自己防火墙是否挡住了这个端口

telnet 自己ip 端口

操作:

1. 关防火墙(不推荐)

2. 向防火墙添加这个端口放过的规则

recv后ctrl+c结束client

78c14c900c6edcbbc67e099167d1a402.png

recv后在新窗口结束client

4dcec6e3e9ab3a73ac84073baf84cbe3.png

0x0002 Server接不上(端口号错、对方ip输错)

报错:

Connect: Network is unreachable

考虑Server防火墙是不是过不去

telnet 对方ip 端口

第二次接同一个Server端口

报错在Connect

[root@localhost 01]# ./client 192.168.80.151 1588

192.168.80.151 : 1588

Connect: Connection refused

接通后再杀死client

Server以非异常方式退出(不报error)

Client:

[root@localhost 01]# ./client 192.168.80.151 1588

192.168.80.151 : 1588

Connect: Success

Enter message to send:^Z

[1]+ 已停止 ./client 192.168.80.151 1588

[root@localhost 01]# ps

PID TTY TIME CMD

8114 pts/0 00:00:00 bash

11288 pts/0 00:00:00 client

11290 pts/0 00:00:00 ps

[root@localhost 01]# kill -9 11288

[root@localhost 01]#

Server:

[root@localhost 01]# ./server 192.168.80.151 1588

192.168.80.151 : 1588

Listening

Accept client 192.168.80.153

[root@localhost 01]#

d610feb70154fbb084e6d764b16cb234.png

接通后杀死Server

Client以正常方式退出(不报error)

Server:

[root@localhost 01]# ./server 192.168.80.151 1588

192.168.80.151 : 1588

Listening

Accept client 192.168.80.153

^C

[root@localhost 01]#

Client:

[root@localhost 01]# ./client 192.168.80.151 1588

192.168.80.151 : 1588

Connect: Success

Enter message to send:HelloServer

received:

Enter message to send:HelloServer

[root@localhost 01]#

0x0003 链接成功后从新会话启动Client

6a8c13d67b1b7ecb88c2cb247ff57968.png

使用指定端口的方式在client和server上都用bind方法

4c61ea402b3b80e8dfd871c4b0895088.png

Client3连接不存在的ip

[root@localhost 03]# ./tcp_client3 192.168.122.1

server_port: 192

server_ip: INADDR_ANY

client_port: 0

Connect: Network is unreachable

255.255.255.255:192

同一张网卡设置多个ip掩码都不在一个网段上能通才怪呢

0x0004 read write recv send

0x0004-1-1Read Write Test

read一旦读完一次缓冲就立刻返回,不能读满后返回

write读到的内容和client相同

ff4573bc3edf56c322f8781c7e623c90.png

0x0004-1-2延时write

00c9e7f4e7d8c3f8b2e5a9d61b39bd5e.png

0x0004-2-1Recv Send Test

recv 和send的主要区别是带有第四个参数能够对阻塞和非阻塞等信息进行控制

MSG_DONTROUTE | 不查找表 |

MSG_OOB | 接受或者发送带外数据 |

MSG_PEEK | 查看数据,并不从系统缓冲区移走数据 |

MSG_WAITALL | 等待所有数据 |

recv和send的结果与read write相同

7e0a95aeaf7cab444b5289662fdc3d94.png

0x0004-2-2延时send

b8688092024f0fa1e942e35e2a3f5b0d.png

0x0005

内核缓冲区测试

测试最大写入write后阻塞

a8d51e0dd07222e9da2a4ac5ea9aef2e.png

netstat 命令及其参数

-a (all)显示所有选项,默认不显示LISTEN相关

-t (tcp)仅显示tcp相关选项

-u (udp)仅显示udp相关选项

-n 拒绝显示别名,能显示数字的全部转化成数字。

-l 仅列出有在 Listen (监听) 的服務状态

-p 显示建立相关链接的程序名

-r 显示路由信息,路由表

-e 显示扩展信息,例如uid等

-s 按各个协议进行统计

-c 每隔一个固定时间,执行该netstat命令。

提示:LISTEN和LISTENING的状态只有用-a或者-l才能看到

setsockopt 函数

设置套接口的选项。

#include

#include

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

sockfd:标识一个套接口的描述字。

level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。

optname:需设置的选项。

optval:指针,指向存放选项待设置的新值的缓冲区。

optlen:optval缓冲区长度。

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

BOOL bReuseaddr=TRUE;

setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));

2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历

TIME_WAIT的过程:

BOOL bDontLinger = FALSE;

setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));

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

int nNetTimeout=1000;//1秒

//发送时限

setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));

//接收时限

setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));

4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节

(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据

和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:

// 接收缓冲区

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));

5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响

程序的性能:

int nZero=0;

setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));

6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):

int nZero=0;

setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));

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

BOOL bBroadcast=TRUE;

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

8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可

以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的

作用,在阻塞的函数调用中作用不大)

BOOL bConditionalAccept=TRUE;

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

9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们

一般采取的措施是"从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置让程序满足具体

应用的要求(即让没发完的数据发送出去后在关闭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));

使用setsockopt调整内核缓冲区的大小后

(不慎调的更小了)

6e8843202ee1bad18622c3720031f018.png

0x0006

0x0006.1

两边都进入read阻塞状态,无法传送数据

3edb8fc210480595270ce4d390432fef.png

0x0006.2

读写大小一致,可以正常传输

17181-000107-W0601.6.2.PNG

读写大小不一致,冗余的数据最后会堵住一边的write

(图相同,省略)

bb1b53dea300439d465b1294a7e96f46.png

0x0006.3

前两种都是正常收发

(省略其他图片)

fd13df717bd4c1434cffc49a3d209744.png

第三种 server 1000 1000 client 700 700

client完成了一轮write read server read都没有做完就阻塞了

0c0f5baff5e9cc0da5bb17bdc6706272.png

0x0006.4

前两种都是正常收发

(同3)

第三种 server 1000 1000 client 700 700

client写完之后阻塞在read server read没有做完,阻塞

d0a0fb78e388891cdc9577a1ec6295b5.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值