信号驱动式的I/O对于TCP套接字近乎无用。问题在于该信号产生的太频繁,并且它的出现没有告诉我们发生了什么事情。
在UDP上使用信号驱动式I/O是简答的。SIGIO信号发生在以下情况:
数据报到时套接字
套接字上发生异步错误
#include "unp.h"
static int sockfd;
#define QSIZE 8
#define MAXDG 4096
typedef struct{
void *dg_data;
size_t dg_len;
struct sockaddr *dg_sa;
socklen_t dg_salen;
}DG;
static DG dg[QSIZE];
static long cntread[QSIZE+1];
static int iget;
static int iput;
static int nqueue;
static socklen_t clilen;
static void sig_io(int);
static void sig_hup(int);
/*
UDP 使用信号驱动是I/O,SIGIO信号在发生以下时间产生:
1.数据报到达套接字;
2.套接字上发生异步错误;( 发生异步错误的前提是UCP套接字已连接 )
*/
static void sig_io (int signo)
{
ssize_t len;
int nread;
DG *ptr;
printf("sig io\n");
for (nread = 0; ;)
{
if (nqueue >= QSIZE){
printf("receive overflow\n");
return ;
}
ptr = &dg[iput];
ptr->dg_salen = clilen;
len = recvfrom(sockfd, ptr->dg_data, MAXDG, 0, ptr->dg_sa, &ptr->dg_salen);
if (len < 0)
{
if (errno==EWOULDBLOCK)
break; /*all done ;no more queued to read*/
else
perror("recvfrom");
}
ptr->dg_len = len;
nread++;
nqueue++;
if (++iput >= QSIZE)
iput = 0;
}
cntread[nread]++; /*histogram of # datagram read per signal*/
}
static void sig_hup(int signo)
{
int i;
printf("signal hup\n");
for (i = 0; i <= QSIZE; i++)
printf("cntread[%d] = %ld\n", i, cntread[i]);
}
void dg_echo(int sockfd_arg, SA *pcliaddr, socklen_t clilen_arg)
{
int i;
const int on = 1;
sigset_t zeromask, newmask, oldmask;
sockfd = sockfd_arg;
clilen = clilen_arg;
for (i = 0; i < QSIZE; i++){ /*init queue of buffers*/
dg[i].dg_data = malloc(MAXDG);
dg[i].dg_sa = malloc(clilen);
dg[i].dg_salen = clilen;
}
iget = iput = nqueue = 0;
signal(SIGHUP, sig_hup);
signal(SIGIO, sig_io);
fcntl(sockfd, F_SETOWN, getpid());/*设置套接字属主*/
ioctl(sockfd, FIOASYNC, &on);
ioctl(sockfd, FIONBIO, &on);
sigemptyset(&zeromask); /*init three signal sets*/
sigemptyset(&oldmask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGIO);/*Signal we want to block*/
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
printf("enter for\n");
for (;;)
{
while (nqueue == 0)
{
sigsuspend(&zeromask); /*wait for datagram to process*/
}
/*unblck sigio*/
sigprocmask(SIG_SETMASK, &oldmask, NULL);
sendto(sockfd, dg[iget].dg_data, dg[iget].dg_len, 0, dg[iget].dg_sa, dg[iget].dg_salen);
if (++iget >= QSIZE)
iget = 0;
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
nqueue--;
}
}
int main()
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(sockfd, (SA *)&servaddr, sizeof(servaddr));
dg_echo(sockfd, (SA *)&cliaddr, sizeof(cliaddr));
return 0;
}
#include "unp.h"
void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
while (fgets(sendline, MAXLINE, fp) != NULL)
{
sendto(sockfd, sendline, strlen(sendline),0, pservaddr, servlen);
n = recvfrom(sockfd, recvline, MAXLINE, 0 ,NULL, NULL);
recvline[n]=0;
fputs(recvline, stdout);
}
}
int main (int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
{
printf("usage:udpcli \n" );
return 0;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (SA*)&servaddr, sizeof(servaddr));
return 0;
}
/* ************************************************************************
* Filename: unp.h
* Description:
* Version: 1.0
* Created: 2018年08月15日 02时44分11秒
* Revision: none
* Compiler: gcc
* Author: YOUR NAME (),
* Company:
* ************************************************************************/
/* include unph */
/* Our own header. Tabs are set for 4 spaces, not 8 */
#ifndef __unp_h
#define __unp_h
//#include "../config.h" /* configuration options for current OS */
/* "../config.h" is generated by configure */
/* If anything changes in the following list of #includes, must change
acsite.m4 also, for configure's tests. */
#include /* basic system data types */
#include /* basic socket definitions */
#if TIME_WITH_SYS_TIME
#include /* timeval{} for select() */
#include /* timespec{} for pselect() */
#else
#if HAVE_SYS_TIME_H
#include /* includes unsafely */
#else
#include /* old system? */
#endif
#endif
#include /* sockaddr_in{} and other Internet defns */
#include /* inet(3) functions */
#include
#include /* for nonblocking */
#include
#include
#include
#include
#include
#include /* for S_xxx file mode constants */
#include /* for iovec{} and readv/writev */
#include
#include
#include /* for Unix domain sockets */
#ifdef HAVE_SYS_SELECT_H
# include /* for convenience */
#endif
#ifdef HAVE_SYS_SYSCTL_H
#ifdef HAVE_SYS_PARAM_H
# include /* OpenBSD prereq for sysctl.h */
#endif
# include
#endif
#ifdef HAVE_POLL_H
# include /* for convenience */
#endif
#ifdef HAVE_SYS_EVENT_H
# include /* for kqueue */
#endif
#ifdef HAVE_STRINGS_H
# include /* for convenience */
#endif
/* Three headers are normally needed for socket/file ioctl's:
* , , and .
*/
//#ifdef HAVE_SYS_IOCTL_H
# include
//#endif
#ifdef HAVE_SYS_FILIO_H
# include
#endif
#ifdef HAVE_SYS_SOCKIO_H
# include
#endif
#ifdef HAVE_PTHREAD_H
# include
#endif
#ifdef HAVE_NET_IF_DL_H
# include
#endif
#ifdef HAVE_NETINET_SCTP_H
#include
#endif
#include
#define LISTENQ 1024 /* 2nd argument to listen() */
/* Miscellaneous constants */
#define MAXLINE 4096 /* max text line length */
#define BUFFSIZE 8192 /* buffer size for reads and writes */
/* Define some port number that can be used for our examples */
#define SERV_PORT 9877 /* TCP and UDP */
#define SERV_PORT_STR "9877" /* TCP and UDP */
/* Following shortens all the typecasts of pointer arguments: */
#define SA struct sockaddr
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
void Listen(int fd, int backlog);
#ifdef HAVE_POLL
int Poll(struct pollfd *fdarray, unsigned long nfds, int timeout);
#endif
ssize_t Recv(int fd, void *ptr, size_t nbytes, int flags);
ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags,
struct sockaddr *sa, socklen_t *salenptr);
ssize_t Recvmsg(int fd, struct msghdr *msg, int flags);
int Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
void Send(int fd, const void *ptr, size_t nbytes, int flags);
void Sendto(int fd, const void *ptr, size_t nbytes, int flags,
const struct sockaddr *sa, socklen_t salen);
void
Sendmsg(int fd, const struct msghdr *msg, int flags);
void
Setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen);
void
Shutdown(int fd, int how);
int
Sockatmark(int fd);
int
Socket(int family, int type, int protocol);
int
Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
const char *
Inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
ssize_t writen(int fd, const void *vptr, size_t n);
void
Writen(int fd, void *ptr, size_t nbytes);
void Close(int fd);
void
Bind(int fd, const struct sockaddr *sa, socklen_t salen);
pid_t Fork(void);
void
Connect(int fd, const struct sockaddr *sa, socklen_t salen);
void
Inet_pton(int family, const char *strptr, void *addrptr);
void
str_cli(FILE *fp, int sockfd);
void
Fclose(FILE *fp);
FILE *
Fdopen(int fd, const char *type);
char *
Fgets(char *ptr, int n, FILE *stream);
FILE *
Fopen(const char *filename, const char *mode);
void
Fputs(const char *ptr, FILE *stream);
ssize_t
Readline(int fd, void *ptr, size_t maxlen);
void
Write(int fd, void *ptr, size_t nbytes);
ssize_t
Read(int fd, void *ptr, size_t nbytes);
#endif /* __unp_h */