13.1 send & recv函数
13.1.1 Linux中的send & recv
#include<sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);
//成功时返回发送的字节数,失败时返回-1
//sockfd 表示数据传输对象的连接的套接字文件描述符
//buf 保存待传输数据的缓冲地址值
//nbytes 待传输的字节数
//flags 传输数据时指定的可选项信息
#include<sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
//成功时返回接收的字节数,失败时返回-1
//sockfd表示数据接收对象的连接套接字文件描述符
//buf保存接收文件的缓冲地址值
//nbytes可接收的最大字节数
//flags接收数据时指定的可选信息项
可选项 | 含义 | send | recv |
---|---|---|---|
MSG_OOB | 用于传输带外数据 | * | * |
MSG_PEEK | 验证输入缓冲中是否存在接收的数据 | * | |
MSG_DONTROUTE | 数据传输过程中不参照路由表,在本地网络中寻找目的地 | * | |
MSG_DONTWAIT | 调用I/O函数时不阻塞,用于使用非阻塞I/O | * | * |
MSG_WAITALL | 防止函数返回,直到接收全部请求的字节数 | * |
13.1.2 MSG_OOB:发送紧急消息
//oob_send.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.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(PF_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);
}
//oob_recv.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<fcntl.h>
#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);
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(recv_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);
}
13.1.3 检查输入缓冲
//peek_send.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
void error_handling(char *message);
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in send_adr;
if(argc!=3){
printf("Usage: %s <IP> <port>\n",argv[0]);
exit(1);
}
sock=socket(PF_INET, SOCK_STREAM, 0);
memset(&send_adr, 0, sizeof(send_adr));
send_adr.sin_family=AF_INET;
send_adr.sin_addr.s_addr=inet_addr(argv[1]);
send_adr.sin_port=htons(atoi(argv[2]));
if(connect(sock, (struct sockaddr*)&send_adr, sizeof(send_adr))==-1)
error_handling("connect() error!");
write(sock, "123", strlen("123"));
close(sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
//peek_recv.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#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);
}
13.2 readv & writev 函数
13.2.1 使用readv & writev函数
writev函数可以将分散保存在多个缓冲中的数据一并发送,通过readv函数可以由多个缓冲分别接收。
#include<sys/uio.h>
ssize_t writev(int filedes, const struct iovec *iov, int ivocnt);
//成功时返回发送的字节数,失败时返回-1
//filedes表示数据传输对象的套接字文件描述符。但该函数并不只限于套接字,因此,可以像read函数一样向其传递文件或标准输出描述符
//iov iovec结构体数组的地址值,结构体iovec中包含待发送的数据的位置和大小信息
//iovcnt向第二个参数传递数组的长度
struct iovec
{
void *iov_base;//缓冲地址
size_t iov_len;//缓冲大小
}
//writev.c
#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;
}
//readv.c
#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 message: %s \n", buf1);
printf("Second message: %s \n", buf2);
return 0;
}