send
函数
ssize_t send(int sockfd, const void * buf, size_t nbytes, int flags)
成功时返回发送的字节数,失败返回-1
sockfd:套接字文件描述符
buf:保存待传输数据的缓冲地址值
nbytes:待传输的字节数
flags:可选项
recv
函数
ssize_t recv(int sockfd, const void * buf, size_t nbytes, int flags)
成功时返回发送的字节数,失败返回-1
sockfd:套接字文件描述符
buf:保存接收数据的缓冲地址值
nbytes:可接收的最大字节数
flags:可选项
MSG_OOB:发送紧急信息
MSG_OOB可选项用于创建特殊发送方法和通道用来发送紧急信息。
发送紧急信息
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[]) {
int sock;
struct sockaddr_in recv_adr;
if (argc != 3) {
printf("usage: %s <IP> <port> \n", argv[0]);
exit(1);
}
sock = socket(AF_INET, SOCK_STREAM, 0);
memset(&recv_adr, 0, sizeof(recv_adr));
recv_adr.sin_family = AF_INET;
recv_adr.sin_addr.s_addr = inet_addr(argv[1]);
recv_adr.sin_port = htons(atoi(argv[2]));
if (connect(sock, (struct sockaddr *)&recv_adr, sizeof(recv_adr)) == -1) {
error_handling("connect() error!!!");
}
write(sock, "123", strlen("123"));
send(sock, "4", strlen("4"), MSG_OOB);
write(sock, "567", strlen("567"));
send(sock, "890", strlen("890"), MSG_OOB);
close(sock);
return 0;
}
void error_handling(char *message) {
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
接收紧急信息
#define BUF_SIZE 30
void error_handling(char *message);
void urg_handler(int signo);
int acpt_sock;
int recv_sock;
int main(int argc, char *argv[]) {
struct sockaddr_in recv_adr, serv_adr;
int str_len, state;
socklen_t serv_adr_sz;
struct sigaction act;
char buf[BUF_SIZE];
if (argc != 2) {
printf("usage: %s <port> \n", argv[0]);
exit(1);
}
act.sa_handler = urg_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
acpt_sock = socket(PF_INET, SOCK_STREAM, 0);
memset(&recv_adr, 0, sizeof(recv_adr));
recv_adr.sin_family = AF_INET;
recv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
recv_adr.sin_port = htons(atoi(argv[1]));
if (bind(acpt_sock, (struct sockaddr*)&recv_adr, sizeof(recv_adr)) == -1) {
error_handling("bind() error!!!");
}
listen(acpt_sock, 5);
serv_adr_sz = sizeof(serv_adr);
recv_sock = accept(acpt_sock, (struct sockaddr*)&serv_adr, &serv_adr_sz);
//文件描述符 recv_sock 指向的套接字引发的 SIGURG 信号处理进程变为将getpid 函数返回值用作 ID 的进程
fcntl(recv_sock, F_SETOWN, getpid());
state = sigaction(SIGURG, &act, 0);
while ((str_len = recv(recv_sock, buf, sizeof(buf), 0)) != 0) {
if (str_len == -1) {
continue;
}
buf[str_len] = 0;
puts(buf);
}
close(recv_sock);
close(acpt_sock);
return 0;
}
void urg_handler(int signo) {
int str_len;
char buf[BUF_SIZE];
str_len = recv(recv_sock, buf, sizeof(buf) - 1, MSG_OOB);
buf[str_len] = 0;
printf("urgent message: %s \n", buf);
}
void error_handling(char *message) {
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
处理 SIGURG 信号时必须指定处理信号的进程,getpid 函数返回调用此函数的进程 ID,指定当前进程为处理 SIGURG 信号的主体。
紧急模式原理
真正意义是督促数据接收对象尽快处理数据。
字符 0 右侧偏移量为 3 的位置有紧急指针,紧急指针指向紧急消息的下一个位置,同时向对方传递如下信息:
紧急指针指向的偏移量为 3 之前的部分就是紧急消息
URG=1:载有紧急消息的数据包
URG 指针:紧急指针位于偏移量为 3 的位置
但是,无法得知紧急消息是 890 还是 90.
检查输入缓冲
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[]) {
int acpt_sock, recv_sock;
struct sockaddr_in acpt_adr, recv_adr;
int str_len, state;
socklen_t recv_adr_sz;
char buf[BUF_SIZE];
if (argc != 2) {
printf("usage: %s <port>\n", argv[0]);
exit(1);
}
acpt_sock = socket(PF_INET, SOCK_STREAM, 0);
memset(&acpt_adr, 0, sizeof(acpt_adr));
acpt_adr.sin_family = AF_INET;
acpt_adr.sin_addr.s_addr = htonl(INADDR_ANY);
acpt_adr.sin_port = htons(atoi(argv[1]));
if (bind(acpt_sock, (struct sockaddr*)&acpt_adr, sizeof(acpt_adr)) == -1) {
error_handling("bind() error !!!");
}
listen(acpt_sock, 5);
recv_adr_sz = sizeof(recv_adr);
recv_sock = accept(acpt_sock, (struct sockaddr*)&recv_adr, &recv_adr_sz);
while (1) {
//读取后不会删除输入缓冲中的数据,因此可以再次读取
str_len = recv(recv_sock, buf, sizeof(buf) - 1, MSG_PEEK | MSG_DONTWAIT);
if (str_len > 0) {
break;
}
}
buf[str_len] = 0;
printf("buffering %d bytes: %s \n", str_len, buf);
str_len = recv(recv_sock, buf, sizeof(buf) - 1, 0);
buf[str_len] = 0;
printf("read again: %s\n", buf);
close(acpt_sock);
close(recv_sock);
return 0;
}
void error_handling(char *message) {
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
运行结果如下:
readv 和 writev 函数
功能:对数据进行整合传输及发送的函数
writev
:将分散在多个缓冲中的数据一并发送
sendv
:由多个缓冲分别接收
ssize_t writev(int filedes, const struct iovec *iov, int iovnt);
filedes: 文件描述符
iov: 结构体数组的地址值
iovnt:第二个参数的数组长度
struct iovec
struct iovec {
void * iov_base; //缓冲地址
size_t iov_len; //缓冲大小
}
其中,_len
表示要发送的缓冲中的数据长度。
#include <stdio.h>
#include <sys/uio.h>
int main(int argc, char *argv[]) {
struct iovec vec[2];
char buf1[] = "ABCDEFG";
char buf2[] = "1234567";
int str_len;
vec[0].iov_base = buf1;
vec[0].iov_len = 3;
vec[1].iov_base = buf2;
vec[1].iov_len = 4;
str_len = writev(1, vec, 2);
puts("");
printf("write bytes: %d \n", str_len);
return 0;
}
运行结果:
#include <stdio.h>
#include <sys/uio.h>
#define BUF_SIZE 100
int main(int argc, char *argv[]) {
struct iovec vec[2];
char buf1[BUF_SIZE] = {0,};
char buf2[BUF_SIZE] = {0,};
int str_len;
vec[0].iov_base = buf1;
vec[0].iov_len = 5;
vec[1].iov_base = buf2;
vec[1].iov_len = BUF_SIZE;
str_len = readv(0, vec, 2);
printf("read bytes: %d\n", str_len);
printf("first msg: %s\n", buf1);
printf("second msg: %s\n", buf2);
return 0;
}
运行结果: