使用SIGURG信号发送接收带外数据
Posted qq_34132502
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用SIGURG信号发送接收带外数据相关的知识,希望对你有一定的参考价值。
在Linux环境下,内核通知应用程序带外数据到达主要有两种方法:
- IO复用技术,select等系统调用在接收到带外数据时将返回,并向应用程序报告socket上的异常事件。
- 使用SIGURG信号
服务端:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <libgen.h>
#define BUF_SIZE 1024
#define BACKLOG 5
static int connfd;
// SIGURG信号的处理函数
void sig_urg(int sig) {
int save_errno = errno;
char buffer[BUF_SIZE];
memset(buffer, '\\0', BUF_SIZE);
int ret = recv(connfd, buffer, BUF_SIZE - 1, MSG_OOB);
printf("got %d bytes of oob data '%s'\\n", ret, buffer);
errno = save_errno;
}
void addsig(int sig, void (*sig_handler)(int)) {
struct sigaction sa;
memset(&sa, '\\0', sizeof(sa));
sa.sa_handler = sig_handler;
sa.sa_flags |= SA_RESTART;
sigfillset(&sa.sa_mask);
assert(sigaction(sig, &sa, NULL) != -1);
}
int main(int argc, char*argv[]) {
if (argc <= 2) {
printf("usage: %s ip_address port_number\\n", basename(argv[0]));
return 1;
}
const char* ip = argv[1];
int port = atoi(argv[2]);
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);
int sock = socket(PF_INET, SOCK_STREAM, 0);
assert(sock >= 0);
int ret = bind(sock, (struct sockaddr*)&address, sizeof(address));
assert(ret != -1);
ret = listen(sock, BACKLOG);
assert(ret != -1);
struct sockaddr_in client;
socklen_t client_addlen = sizeof(client);
connfd = accept(sock, (struct sockaddr*)&client, &client_addlen);
if (connfd < 0) {
printf("errno is %d\\n",errno);
}
else {
addsig(SIGURG, sig_urg);
// 使用SIGURG信号之前,我们必须设置socket的宿主进程或进程组
fcntl(connfd, F_SETOWN, getpid());
char buffer[BUF_SIZE];
while (1)
{
// 循环接收普通数据
memset(buffer, '\\0', BUF_SIZE);
ret = recv(connfd, buffer, BUF_SIZE - 1, 0);
if (ret <= 0) {
printf("ret <= 0\\n");
break;
}
printf("got %d bytes of normal data '%s'\\n", ret, buffer);
}
close(connfd);
}
close(sock);
return 0;
}
客户端发送带外数据、普通数据:
#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>
#include <libgen.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
if (argc <= 2) {
printf("usage: %s ip_address port_number\\n", basename(argv[0]));
return 1;
}
const char* ip = argv[1];
int port = atoi(argv[2]);
struct sockaddr_in server_address;
bzero(&server_address, sizeof(struct sockaddr_in));
server_address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &server_address.sin_addr);
server_address.sin_port = htons(port);
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
assert( sockfd >= 0);
if (connect(sockfd, (struct sockaddr*)&server_address, sizeof(struct sockaddr_in)) < 0) {
printf("connection failed\\n");
} else {
const char* oob_data = "abc";
const char* normal_data = "123";
send(sockfd, normal_data, strlen(normal_data), 0);
send(sockfd, oob_data, strlen(oob_data), MSG_OOB);
send(sockfd, normal_data, strlen(normal_data), 0);
}
close(sockfd);
return 0;
}
带外数据
- 使用带有
MSG_OOB
标志的send
/recv
系统调用来发送 / 接收带外数据 - 使用IO复用系统调用或
SIGURG
信号检测带外数据是否到达; - 使用
int sockatmark(int sockfd)
系统调用判断一个socket是否处于带外标记,即下一个被读取到的数据是否是带外数据。
以上是关于使用SIGURG信号发送接收带外数据的主要内容,如果未能解决你的问题,请参考以下文章