2008年8月13日 星期三

實現SIGIO驅動的socket範例

此程式由realtang所撰寫的,實現非同步的UDP Socket做法。
在接收到資料及檢測到異常時,引發SIGIO訊號。
SIGIO訊號是非同步傳輸的專用訊號。

Server端程式碼:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h> /*socket address struct*/
#include <arpa/inet.h> /*host to network convertion*/
#include <sys/socket.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/ioctl.h>
#define MAX_TRANSPORT_LENTH 512

static int g_var = 0;
static int g_skt = 0;
void sig_handler(int signum)
{
char  buf[MAX_TRANSPORT_LENTH+1] = "";
int len = 0;
len = read(g_skt,buf,MAX_TRANSPORT_LENTH);
if (len<0)
{
perror("Read socket failed");
exit(-1);
}
else
{
printf("In SIGIO handler,got msg:%s\n",buf);
}
}

int main()
{
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
addr.sin_family =  AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(50001);

signal(SIGIO,sig_handler);

g_skt = socket(AF_INET,SOCK_DGRAM,0);
if(g_skt == -1)
{
perror("Create socket failed");
exit(-1);
}

int len = sizeof(addr);
int ret = 0;

int on = 1;
    ret = fcntl(g_skt, F_SETOWN, getpid());//Set process or process group ID to receive SIGIO signals
if(-1 == ret)
{
perror("Fcntl F_SETOWN failed");
exit(-1);
}
    ret = ioctl(g_skt, FIOASYNC, &on);
if(-1 == ret)   
{
perror("Fcntl FIOASYNC failed");
exit(-1);
}   
    ret = ioctl(g_skt, FIONBIO, &on);
if(-1 == ret)   
{
perror("ioctl FIONBIO failed");
exit(-1);
}

ret = bind(g_skt,(struct sockaddr *)&addr,sizeof(addr));
if(-1 == ret)
{
perror("Bind socket failed");
exit(-1);
}
while(1)
{
printf("I am running\n");
sleep(2);
}
close(g_skt);
}

Client端程式碼:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>   /*socket address struct*/
#include <arpa/inet.h>   /*host to network convertion*/
#include <sys/socket.h>
#include <signal.h>
#define MAX_TRANSPORT_LENTH 512

int main()
{
 struct sockaddr_in addr;
 memset(&addr,0,sizeof(addr));
 addr.sin_family =  AF_INET;
 addr.sin_addr.s_addr = inet_addr("192.168.1.106");
 addr.sin_port = htons(50001);
 
 int sock;
 sock = socket(AF_INET,SOCK_DGRAM,0);
 if(sock == -1)
 {
  perror("Create socket failed");
  exit(-1);
 }
 
 int ret;
 ret = connect(sock,(struct sockaddr *)&addr,sizeof(addr));
 if(ret == -1)
 {
  perror("Connect socket failed");
  exit(-1);  
 }  
 while(1)
 {
  printf("Will send messge to server\n");
  write(sock,"Some unknown infomation\n",MAX_TRANSPORT_LENTH);
  sleep(1);
 }
 
}

daemon修改後的Server版本:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#define MAX_LENTH 1500

static int nqueue = 0;
void sigio_handler(int signum)
{
if (signum = SIGIO)
nqueue++;
return;
}

static recv_buf[MAX_LENTH];
int main(int argc, char *argv[])
{
int sockfd, on = 1;
struct sigaction action;
sigset_t newmask, oldmask;
struct sockaddr_in addr;

memset(&addr, 0, sizeof(addr));
addr.sin_family =  AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(50001);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Create socket failed");
exit(-1);
}
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("Bind socket failed");
exit(-1);
}

memset(&action, 0, sizeof(action));
action.sa_handler = sigio_handler;
action.sa_flags = 0;
sigaction(SIGIO, &action, NULL);
if (fcntl(sockfd, F_SETOWN, getpid()) == -1) {
perror("Fcntl F_SETOWN failed");
exit(-1);
}
if (ioctl(sockfd, FIOASYNC, &on) == -1) {
perror("Ioctl FIOASYNC failed");
exit(-1);
}

        sigemptyset(&oldmask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGIO);
while (1) {
int len;
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
while (nqueue == 0)
sigsuspend(&oldmask);
len = recv(sockfd, recv_buf, MAX_LENTH, MSG_DONTWAIT);
if (len == -1 && errno == EAGAIN)
nqueue = 0;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
if (len >= 0)
printf("recv %d byte(s)\n", len);

}
}

資料來源:
http://www.linuxsir.org/bbs/showthread.php?t=214611

沒有留言: