TCP带外数据测试

带外数据的应用情况

如果发送客户端程序由于一些原因需要取消已经写入服务器的请求,那么他就需要向服务器紧急发送一个标识取消的请求。

使用带外数据的实际程序例子就是telnet,rlogin,ftp命令。

前两个程序(telnet和rlogin)会将中止字符作为紧急数据发送到远程端。这会允许远程端冲洗所有未处理的输入,并且丢弃所有未发送的终端输出。这会快速中断一个向我们屏幕发送大量数据 的运行进程。

ftp命令使用带外数据来中断一个文件的传输。

TCP的带外数据(TCP紧急数据)

TCP协议没有真正意义上的带外数据.为了发送重要协议,TCP提供了一种称为紧急模式(urgent
mode)的机制.TCP协议在数据段中设置URG位,表示进入紧急模式.接收方可以对紧急模式采取特殊的处理.很容易看出来,这种方式数据不容易被阻塞,可以通过在我们的服务器端程序里面捕捉SIGURG信号来及时接受数据或者使用带OOB标志的recv函数来接受.

OOBServer.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>

/* 服务器要监听的本地端口 */
#define MYPORT 4000
/* 能够同时接受多少没有 accept 的连接 */
#define BACKLOG 10
int new_fd = -1;// 全局变量 连接套接字 主函数和SIGURG信号处理函数中均会调用
void sig_urg(int signo);

void main()
{
/* 在 sock_fd 上进行监听,new_fd 接受新的连接 */
int sockfd;
/* 自己的地址信息 */
struct sockaddr_in my_addr;
/* 连接者的地址信息*/
struct sockaddr_in their_addr;
int sin_size;
int n ;
char buff[100] ;
/* 用于存储以前系统缺省的 SIGURL 处理器的变量 */
void * old_sig_urg_handle ;
/* 这里就是我们一直强调的错误检查.如果调用 socket() 出错,则返回 */

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{/* 输出错误提示并退出 */
perror("socket");
exit(1);
}
/* 主机字节顺序 */
my_addr.sin_family = AF_INET;
/* 网络字节顺序,短整型 */
my_addr.sin_port = htons(MYPORT);
/* 将运行程序机器的 IP 填充入 s_addr */
my_addr.sin_addr.s_addr = INADDR_ANY;
/* 将此结构的其余空间清零 */
bzero(&(my_addr.sin_zero), 8);
/* 这里是我们一直强调的错误检查!! */
if (bind(sockfd, (struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1)
{
/* 如果调用 bind()失败,则给出错误提示,退出 */
perror("bind");
exit(1);
}
/* 这里是我们一直强调的错误检查!! */
if (listen(sockfd, BACKLOG) == -1)
{
/* 如果调用 listen 失败,则给出错误提示,退出 */
perror("listen");
exit(1);
}

/* 设置 SIGURG 的处理函数 sig_urg */
old_sig_urg_handle = signal(SIGURG, sig_urg);
/* 将我们的进程创建为套接口的拥有者 */ //wrong;非监听套接字
/*if(fcntl(sockfd, F_SETOWN, getpid())==-1)
{
perror("fcntl");
exit(1);
}*/

while(1)
{
/* 这里是主 accept()循环 */
sin_size = sizeof(struct sockaddr_in);

/* 这里是我们一直强调的错误检查!! */
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)
{
/* 如果调用 accept()出现错误,则给出错误提示,进入下一个循环 */
perror("accept");
continue;
}
//printf("in main, new_fd = %d\n",new_fd);
fcntl(new_fd,F_SETOWN,getpid());//将我们的进程设置为(连接套接字)的拥有者

/* 服务器给出出现连接的信息 */
printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));
/* 这里将建立一个子进程来和刚刚建立的套接字进行通讯 */
//if (!fork())
if (1)
{
while(1)
{
if((n=recv(new_fd,buff,sizeof(buff)-1,0)) == 0)
{
printf("received EOF\n");
break;
}
buff[n] ='\0';
printf("Recv %d bytes: %s\n", n, buff);
}
}
/* 关闭 new_fd 代表的这个套接字连接 */
close(new_fd);
}
/* 等待所有的子进程都退出 */
while(waitpid(-1,NULL,WNOHANG) > 0);
/* 恢复系统以前对 SIGURG 的处理器 */
signal(SIGURG, old_sig_urg_handle);
}

void sig_urg(int signo)
{
int n;
char buff[100];
printf("SIGURG received\n");
//printf("in sig_urg(),new_fd = %d\n",new_fd);
//while((n = recv(new_fd,buff,sizeof(buff)-1,MSG_OOB)) == -1);
n = recv(new_fd,buff,sizeof(buff)-1,MSG_OOB);
if(n>0)
{
buff[n]='\0';
printf("recv %d OOB byte: %s\n",n,buff);
}
else
{
perror("recv");
}

}

OOBClient.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
/* 服务器程序监听的端口号 */
#define PORT 4000
/* 我们一次所能够接收的最大字节数 */
#define MAXDATASIZE 100
int main(int argc, char *argv[])
{
/* 套接字描述符 */
int sockfd,numbytes;
char buf[MAXDATASIZE];
struct hostent *he;
/* 连接者的主机信息 */
struct sockaddr_in their_addr;
/* 检查参数信息 */
if (argc != 2)
{
/* 如果没有参数,则给出使用方法后退出 */
fprintf(stderr,"usage: client hostname\n");
exit(1);
}
/* 取得主机信息 */
if ((he=gethostbyname(argv[1])) == NULL)
{
/* 如果 gethostbyname()发生错误,则显示错误信息并退出 */
herror("gethostbyname");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
/* 如果 socket()调用出现错误则显示错误信息并退出 */
perror("socket");
exit(1);
}
/* 主机字节顺序 */
their_addr.sin_family = AF_INET;
/* 网络字节顺序,短整型 */
their_addr.sin_port = htons(PORT);
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
/* 将结构剩下的部分清零*/
bzero(&(their_addr.sin_zero), 8);
if(connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
{
/* 如果 connect()建立连接错误,则显示出错误信息,退出 */
perror("connect");
exit(1);
}

if (send(sockfd, "5", 1, MSG_OOB)== -1)
{
perror("send");
close(sockfd);
exit(0);
}
printf("Send 1 byte of OOB data\n");
sleep(2);
/* 这里就是我们说的错误检查! */
if (send(sockfd, "123", 3, 0) == -1)//   123  normal data
{
/* 如果错误,则给出错误提示,然后关闭这个新连接,退出 */
perror("send");
close(sockfd);
exit(0);
}
printf("Send 3 byte of normal data\n");
/* 睡眠 1 秒 */
sleep(2);
if (send(sockfd, "4", 1, MSG_OOB)== -1)
{
perror("send");
close(sockfd);
exit(0);
}
printf("Send 1 byte of OOB data\n");
sleep(2);
if (send(sockfd, "56", 2, 0) == -1)//  56  normal data
{
perror("send");
close(sockfd);
exit(0);
}
printf("Send 2 bytes of normal data\n");
sleep(2);
if (send(sockfd, "7", 1, MSG_OOB)== -1)
{
perror("send");
close(sockfd);
exit(0);
}
printf("Send 1 byte of OOB data\n");
sleep(2);
if (send(sockfd, "89", 2, MSG_OOB)== -1)
{
perror("send");
close(sockfd);
exit(0);
}
printf("Send 2 bytes of OOB data\n");
sleep(2);
/*
if (send(sockfd, "ABC", 3, MSG_OOB)== -1)
{
perror("send");
close(sockfd);
exit(0);
}
printf("Send 3 bytes of OOB data\n");
sleep(2);
if (send(sockfd, "abc", 3, MSG_OOB)== -1)
{
perror("send");
close(sockfd);
exit(0);
}
printf("Send 3 bytes of OOB data\n");
sleep(2);
*/
close(sockfd);
return 0;
}

运行结果:

笔记:

1.收发带外数据

01.发送方如何发送带外数据

注意TCP一次所发送的数据中,可能只包含了TCP的URG标志,却没有包含我们所发送的OOB数据(当发送数据队列中再OOB前面的数据已经达到TCP数据包的长度限制)。

if(send(new_fd, "4", 1, MSG_OOB)== -1)

{

perror("send");

close(new_fd);

exit(0);

}

printf("Send1 byte of OOB data\n");

02.接收方如何接收带外数据

/*设置 SIGURG的处理函数 sig_urg */

old_sig_urg_handle= signal(SIGURG, sig_urg);

voidsig_urg(int signo)

{

intn;

charbuff[100] ;

printf("SIGURGreceived\n");

n = recv(new_fd, buff,sizeof(buff)–1, MSG_OOB);

buff[ n ] = 0 ;

printf("recv%d OOB byte: %s\n", n, buff);

}

2.send(sendfd,"ABC",3,MSG_OOB),将发送3个字节的带外数据OOB数据.但是这里TCP又只支持一个字节的OOB,难道丢掉2个字节?

TCP将把紧急模式URG 置位,紧急指针定位第三个字节("C")(这里不管它的具体位置,紧急指针的作用就是提供定位那个OOB字节的信息),前两个字节("AB")当作普通字节发送.其实TCP总是把最后一个字节当作OOB数据,其他的当作普通字节.不管你通过带MSG_OOB标志的sendxxx函数发送多少字节带外数据OOB数据,发送端只把最后一个字节当作OOB数据,接收端也只能收到一个字节的OOB数据.

3. fcntl(new_fd,F_SETOWN,getpid());//将我们的进程设置为(连接套接字,而不是 监听套接字)的拥有者

4.创建子进程接收普通数据时,带外数据不能正常接收。。。

附:

信号的处理

UNIX 的系统调用 signal()用于接收一个指定类型的信号,并可以指定相应的方法。这就是说,signal()能够将指定的处理函数与信号向关联

函数原型

int signal(int sig,_sighanler_t handler);//sig为需要处理的信号类型,handler为与信号关联的动作,可以是函数地址,也可以是SIG_IGN(忽略信号),SIG_DFL(恢复系统对信号的默认处理).

函数返回值

如果执行成功,则返回信号在此次signal调用之前的关联。

Eg:

void sig_urg(int signo);

/* 用于存储以前系统缺省的 SIGURL
处理器的变量 */

void * old_sig_urg_handle ;

/* 设置 SIGURG 的处理函数 sig_urg*/

old_sig_urg_handle = signal(SIGURG,sig_urg);

******

***数据处理工作****.

******

/* 恢复系统以前对 SIGURG 的处理器 */

signal(SIGURG, old_sig_urg_handle);

(2)在一个套接字上使用信号驱动 I/O 操作

让内核在文件描述符(此处即套接字)就绪的时候使用信号来通知我们。

为了在一个套接字上使用信号驱动 I/O
操作,下面这三步是所必须的。

(1)一个和SIGIO信号的处理函数必须设定。

(2)套接字的拥有者(所属进程)必须被设定。一般来说是使用fcntl函数的
F_SETOWN 参数来进行设定拥有者。以便有明确的进程来接收当某个套接字就绪时发出的信号。

(3)套接字必须被允许使用异步 I/O。一般是通过调用 fcntl 函数的 F_SETFL
命令,O_ASYNC为参数来实现。

Eg:

1.首先,为SIGIO信号设置一个处理函数,用来读取并处理位于输入缓存中的数据。

signal ( SIGIO , void ( * getmyinput ) ( int signum ) );

2.设置一个用来接受SIGIO信号的进程。用fcntl函数。

fcntl ( my_fd , F_SETOWN, getpid() );

3.得到文件描述符的状态标志集,为该状态标志集添加一个O_ASYNC属性。

int  flags = fcntl ( my_fd ,F_GETFL);

fcntl ( my_fd , F_SETFL , flags | O_ASYNC);

TCP带外数据测试,布布扣,bubuko.com

时间: 2024-10-01 04:16:59

TCP带外数据测试的相关文章

TCP带外数据学习总结(概念,发送接收过程,数据到达检测,代码实现)

最近在学习<Linux高性能服务器编程> 这本书,书中零零散散的讲了TCP带外数据的一些知识,在这里把这些知识总结以下,方便自己,也方便他人. 本文主要分为以下四个方面总结,分别为 TCP带外数据的概念,如何发送和接收带外数据,怎么检测带外数据的到达,最后介绍相关函数以及代码实现. 第一部分: TCP带外数据的概念 有很多传输层此协议都具有带外数据(OUT Of Band) 的概念,其作用是迅速通告通信的另一方本段发生的重要事件.带外数据具有比普通数据更高的优先级,理论上应该被立即发送和立即接

TCP带外数据(URG,MSG_OOB)

前言: blog原文地址:http://blog.csdn.net/ordeder/article/details/43243425 本文系读书笔记,主要参考材料:http://wenku.baidu.com/view/f04a4dff9e31433239689341.html TCP的带外数据: 头部标志: URG位,紧急指针. 数据包中:一个紧急指针只指向一个字节的带外数据的后已字节位置.紧急数据时插在正常数据流中进行传输.紧急指针用于指出带外数据字节在正常字节流中的位置. 问题:为何不直接

TCP带外数据

传输层协议使用带外数据(out-of-band,OOB)来发送一些重要的数据,如果通信一方有重要的数据需要通知对方时,协议能够将这些数据快速地发送到对方.为了发送这些数据,协议一般不使用与普通数据相同的通道,而是使用另外的通道.linux系统的套接字机制支持低层协议发送和接受带外数据.但是TCP协议没有真正意义上的带外数据.为了发送重要协议,TCP提供了一种称为紧急模式(urgentmode)的机制.TCP协议在数据段中设置URG位,表示进入紧急模式.接收方可以对紧急模式采取特殊的处理.很容易看

TCP带外数据读写

#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> int main( int argc, char* argv[] ) {

《网络编程》带外数据

带外数据 有些传输层协议具有带外(Out Of Band,OOB)数据的概念,用于迅速通告对端本端所发生的重要事件.因此,带外数据比普通数据(也称为带内数据)有更高的优先级,它应该总是立即被发送,而不论发送缓冲区中是否有排队等待发送的普通数据或因流量控制而导致发送端的通告窗口大小为 0(即停止发送数据) .带外数据的传输可以使用一条独立的传输层连接,也可以映射到传输普通数据的连接中. UDP 没有实现带外数据传输,TCP 也没有真正的带外数据.只不过 TCP 利用其首部中的 紧急指针标志 和 紧

微软公布带外安全更新MS14-068

?? 11月19日,微软公布了带外更新MS14-068以解决Windows 系统中的一个安全漏洞,该补丁安全等级为"严重". MS14-068 | Kerberos 中的漏洞可能同意特权提升 该安全更新攻克了Windows Kerberos KDC 中一个秘密报告的漏洞. 该漏洞可能同意普通域账户提升特权,进而获得域管理员的权限.攻击者要想成功利用该漏洞.其必须首先又有一个有效的域账户.针对该漏洞,微软已经发现有限的攻击行为. 我们建议用户尽快安装该补丁.有关该补丁的具体信息,请參照以

linux中telnet 带外管理服务器的设置

带外操作就相当于交换机路由器中的管理一样的. 首先我们要先进入Linux中.我的Linux是虚拟机这是我首先告诉大家的. 1第一步:先把磁盘挂载到 /mnt中 rpm –qa|grep xinetd   (查看安装的安装包) telnet 的主程序安装包是 xinetd-2.3.14-10.e15 telnet-server-0.17-39.e15.i386.rpm x现在就安装好了 他的配置文件在/etc/xinetd.d/telnet/中 把配置文件中的diasble=yes 改为no 这样

IT设备的救命稻草-如何正确构建OOB带外网络

现实生活中,无论是传统的大型园区网络,运营商.或是现今流行的数据中心.虚拟化等技术,往往归根结底都是大量的网络设备以及服务器堆叠而成.自然而然,当网络或者服务器因为软件故障或者人为操作失误的原因导致系统宕机后,如何第一时间登陆到故障设备,并快速恢复业务已经成为考验运维人员的一大难题. 其实,试想如果网络中存在一个完善的OOB带外网络,在故障发生时,网络控制中心可通过此网络登录网络设备或者服务器的带外管理接口或者Console接口.从而第一时间获取故障信息并予以修正,或者收集log文件上报厂家.岂

各品牌服务器的默认带外BMC管理地址

连接网段到sugon服务器的带外BMC管理端,在本地网络的属性中,选择ipv4更改使用固定IP地址10.0.0.5和默认的10.0.0.10为同一个网段, 然后在浏览器输入默认的地址:10.0.0.10 sugon TC6600   默认的带外管理地址 10.0.0.10   帐号:admin 密码:admin  (采用连接网线的方式) dell R930默认的带外管理地址: 192.168.0.120    帐号:root  密码:calvin  (采用连接网线的方式) H3C 设置带外管理的