引言
- 只有TCP才有带外数据,UDP是没有的。
- 网上也有一种说法,TCP没有真正意义上的“带外数据”。这种说法的由来是在TCP协议中,服务端与客户端之间都通过管道传输数据,比如传输的数据是1字节,没有超过socket中设置的缓冲池的限制的话,这个数据是要等到数据达到缓冲区上限才可以到达对端的。而“带外数据”也并没有什么捷径,也是一样通过这种方法到达对端,只不过会将其标志为紧急数据,提前让对端释放缓冲池内容。
- 需要注意的是,每条紧急数据只能是1字节
如何发送/接收带外数据
发送函数:
#include "head4sock.h"
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#define MAXLINE 80
void usage(const char *info)
{
printf("Usage: %s <srv's IP> <srv's PORT>\n", info);
exit(0);
}
int main(int argc, char **argv)
{
if(argc != 3)
usage(argv[0]);
// tcp
int sockfd;
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in srvaddr;
bzero(&srvaddr, sizeof srvaddr);
srvaddr.sin_family = AF_INET;
inet_pton(AF_INET, argv[1],
(struct sockaddr *)&srvaddr.sin_addr);
srvaddr.sin_port = htons(atoi(argv[2]));
Connect(sockfd, (struct sockaddr *)&srvaddr,
sizeof srvaddr);
while(1)
{
write(sockfd, "123", 3); //发送普通数据
sleep(1);
send(sockfd, "4", 1, MSG_OOB); //MSG_OOB设置为紧急数据
sleep(1);
write(sockfd, "56", 2); //发送普通数据
sleep(1);
send(sockfd, "78", 2, MSG_OOB); //7是普通数据,8是紧急数据
sleep(1);
}
return 0;
}
接收函数:
#include "head4sock.h"
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <strings.h>
#include <signal.h>
#define MAXSIZE 80
static int connfd;
void usage(const char *info)
{
printf("Usage: %s <PORT>\n", info);
exit(0);
}
void catch_sig(int sig)
{
if(sig == SIGURG)
{
char buf[MAXSIZE] = {0};
recv(connfd, buf, MAXSIZE, MSG_OOB); //读出紧急数据
printf("urgent data: %s\n", buf);
}
}
int main(int argc, char **argv)
{
if(argc != 2)
usage(argv[0]);
// tcp
int sockfd;
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
int on = 1;
Setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
int a = 100;
Setsockopt(sockfd, SOL_SOCKET, SO_RCVLOWAT, &a, sizeof a); //设置接收缓冲区为100
struct sockaddr_in srvaddr, cliaddr;
bzero(&srvaddr, sizeof srvaddr);
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
srvaddr.sin_port = htons(atoi(argv[1]));
Bind(sockfd, (struct sockaddr *)&srvaddr,
sizeof srvaddr);
Listen(sockfd, 5);
socklen_t len;
char buf[MAXSIZE];
len = sizeof cliaddr;
bzero(&cliaddr, len);
connfd = Accept(sockfd, (struct sockaddr *)&cliaddr, &len);
/********************************/
signal(SIGURG, catch_sig); //如果有紧急数据来到,则会有信号SIGURG,运行catch_sig
fcntl(connfd, F_SETOWN, getpid());
/********************************/
printf("new connection: %s:%hu\n",
inet_ntoa(cliaddr.sin_addr),
ntohs(cliaddr.sin_port));
int n;
while(1)
{
bzero(buf, MAXSIZE);
if((n=read(connfd, buf, MAXSIZE)) <= 0)
break;
write(STDOUT_FILENO, buf, strlen(buf));
write(STDOUT_FILENO, "\n", 1);
}
return 0;
}
代码运行结果:
带外数据的主要作用:
- 从这个实验中可以知道带外数据的大小只能是1字节,因此带外数据并不是用来传送数据的,一般用于传送一些控制信息表示不同的含义。
- 比如流媒体文件中,大部分信息都为媒体文件信息,但是中间可以包含带外数据(控制信息)