一个客户端的完整程序

1 信号函数 sigaction()

1.1 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

  1. 函数作用 :: 在接收到参数signum指定的信号后应该采取的行动。sigaction至少包括下面几个成员 :
struct sigaction {
                  void (*sa_sigaction)(int, siginfo_t *, void *);
                  sigset_t sa_mask;
                  int sa_flags;
              }

说明

sigaction函数设置与信号signum关联。如果oldact不是指针,sigaction将会把原来的信号保存到oldact所指的位置。如果为空,不动作。

  • sa_sigaction是一个函数指针,它指向接收到信号signum时将被调用的的信号处理函数。 可以特殊值SIG_ING和SIG_DFL
  • sa_mask字段指定了一个信号集, 在调用sa_handler所指向的信号处理函数之前,该信号集将被加入到进程的信号屏蔽中。它可以防止信号在它的处理函数还未运行结束时就被接收到情况,它可以消除这一竞态条件。
  • sa_flags 可以重置调用前的信号,一般为0,也可是SA_RESETHAND,还可以是其他的,具体看说明。
  1. 一个简单程序
#include <signal.h>

#include <stdio.h>
#include <unistd.h>

void ouch(int sig)
{
    printf("OUCH! - I got signal %d/n", sig);
}

int main()
{

    struct sigaction act;

    /*设置必要的参数*/
    act.sa_handler = ouch;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

   if( sigaction(SIGINT, &act, 0) == -1 )

   {
    printf("error!/n");
    return -1;
   }


  while(1) {
    printf("Hello World!/n");
    sleep(1);
  }
}

按下Ctrl+C可以看到一条消息。按Ctrl+退出。

2 定时器

#include <sys/time.h>

int getitimer(int which, struct itimerval *value); int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);

取值含义信号发送
ITIMER_REAL定时真实时间,与alarm类型相同。SIGALRM
ITIMER_VIRT定时进程在用户态下的实际执行时间。SIGVTALRM
ITIMER_PROF定时进程在用户态和核心态下的实际执行时间SIGPROF
setitimer设置的定时器则不同,它们不但可以计时到微妙(理论上),
 还能自动循环定时。在一个Unix进程中,不能同时使用alarm和
ITIMER_REAL类定时器。
  结构itimerval描述了定时器的组成: 
struct itimerval 
{
    struct tim. it_interval;    /* 下次定时取值 */
    struct tim. it_value;     /* 本次定时设置值 */
}
   结构tim.描述了一个精确到微妙的时间: 

struct tim. 
{
    long    tv_sec;    /* 秒(1000000微秒) */
    long    tv_usec;    /* 微妙 */
}
函数setitimer设置一个定时器,参数value指向一个itimerval结构,
 该结构决定了设置的定时器信息,结构成员it_value指定
首次定时的时间,结构成员it_interval指定下次定时的时间。定时器工作时,
先将it_value的时间值减到0,发送一个信号,再将
it_value赋值为it_interval的值,重新开始定时,如此反复。
如果it_value值被设置为0,则定时器停止定时;如果
it_value值不为0但it_interval值为0,则定时器在一次定时后终止。
  函数setitimer调用成功时返回0,否则返回-1,参数ovalue如果不为空,
返回上次的定时器状态。
  函数getitimer获取当前的定时器状态,整型参数which指定了读取的定时器类型,
参数value返回定时器状态。函数调用成功返回0,否则返回-1。

例1. 设置一个定时器,每2.5秒产生一个SIGALRM信号。
  答:将itimerval结构的成员it_interval和成员it_value均赋值为2.5秒即可:
struct itimerval value;
value.it_value.tv_sec=2;
value.it_value.tv_usec=500000;
value.it_interval.tv_sec=2;
value.it_interval.tv_usec=500000;
setitimer(ITIMER_REAL, &value, NULL);
  函数setitimer设置的定时器可以重复定时,无需多次调用。
  例2. 设置一个定时器,进程在用户态下执行1秒钟后发出首次信号,以后进程每在
用户态下执行3秒钟,发送一个信号。
  答:将itimerval结构的成员it_value均赋值为1秒,成员it_interval赋值为3秒即可:
struct itimerval value;
value.it_value.tv_sec=1;
value.it_value.tv_usec=0;
value.it_interval.tv_sec=3;
value.it_interval.tv_usec=0;
setitimer(ITIMER_VIRT, &value, NULL);
  例3. 取消一个ITIMER_PROF类定时器。
  答:将itimerval结构的成员it_value均赋值为0秒即可:
struct itimerval value;
value.it_value.tv_sec=1;
value.it_value.tv_usec=0;
setitimer(ITIMER_PROF, &value, NULL);
  例4. 设置一个定时1.5秒的真实时间定时器,它仅发送一次信号就自动取消。
  答:将itimerval结构的成员it_value均赋值为1.5秒,成员it_interval赋值为0秒即可:
struct itimerval value;
value.it_value.tv_sec=1;
value.it_value.tv_usec=500000;
value.it_interval.tv_sec=0;
value.it_interval.tv_usec=0;
setitimer(ITIMER_REAL, &value, NULL);

一个简单的函数:

 /*  安装定时器 /
static int  InitAlarm(int nTimerSec)
{ 
	struct itimerval struValue;

  	
	if(nTimerSec < 0)
	{
		print("安装定时器时间太小错误 %d/n", nTimerSec);
		return -1;
	}
	struValue.it_value.tv_sec = nTimerSec;
	struValue.it_value.tv_usec = 0;
	struValue.it_interval = struValue.it_value;
	
	if(setitimer(ITIMER_REAL, &struValue, NULL) == -1)
	{
		print( "setitimer 安装定时器错误 /n/t错误代码 = [%d] 错误信息 =[%s]/n",/

                errno,strerror(errno));
		return EXCEPTION;
	}
	return NORMAL;
}

3 客户端程序四个步骤

3.1 创建套接字

sockfd = socket(AF_INET, SOCK_STREAM, 0);

3.2 命令套接字

要用到的几个函数:

struct in_addr {
                      unsigned long int s_addr;

              }
The hostent structure is defined in <netdb.h> as follows:

              struct hostent {
                      char    *h_name;        /* official name of host */

                      char    **h_aliases;    /* alias list */
                      int     h_addrtype;     /* host address type */
                      int     h_length;       /* length of address */

                      char    **h_addr_list;  /* list of addresses */
              }
              #define h_addr  h_addr_list[0]  /* for backward compatibility */
函数名原型作用
inet_atonint inet_aton(const char *cp, struct in_addr *inp);inet_aton() converts the Internet host address cp from the standard numbers-and-dots notation into binary data and stores it in the structure that inp points
gethostbynamestruct hostent *gethostbyname(const char *name); 
htonluint16_t htons(uint16_t hostshort);converts the unsigned short integer netshort from network byte order to host byte order

3.3 连接

用connect函数

#include <sys/types.h>

#include <sys/socket.h>
int  connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);

3.4 发送数据

用write函数

#include <unistd.h>
 ssize_t write(int fd, const void *buf, size_t count);

3.5 接收数据

用read函数

#include <unistd.h>
 ssize_t read(int fd, void *buf, size_t count);

4 一个完整的客户端程序

这个演示程序中,增加了定时功能, 头文件中有些没有用到,但也包含进去了,主要是不想改了。
/*
 * 公共包含的头文件
 */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <ctype.h>
#include <math.h>
#include <fcntl.h>

#include <dlfcn.h>
#include <stdarg.h>
#include <dirent.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>

#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ipc.h>
#include <sys/shm.h> 

#include <sys/sem.h>
#define  DEF_COM_TIMEOUT 60

/*
 * RESULT变量宏定义
 */
#define NORMAL    	0
#define EXCEPTION 	-1
#define INVALID   	-2

/*

 * BOOL变量宏定义
 */
#define BOOLTRUE  	1
#define BOOLFALSE 	0

/*
 * 基本类型定义
 */
#ifndef MFC
typedef void           VOID;
typedef const void     CVOID;
#endif

typedef void *         PVOID;
typedef const void *   PCVOID;

typedef char           CHAR;
typedef CHAR *         PCHAR;
typedef const CHAR     CCHAR;
typedef const CHAR *   PCCHAR;

typedef int            INT;
typedef INT *          PINT;
typedef const INT      CINT;
typedef const INT *    PCINT;

typedef short          SHORT;
typedef SHORT *        PSHORT;
typedef const SHORT    CSHORT;
typedef const SHORT *  PCSHORT;

typedef long           LONG;
typedef LONG *         PLONG;
typedef const LONG     CLONG;
typedef const LONG *   PCLONG;

typedef float          FLOAT;
typedef FLOAT *        PFLOAT;
typedef const FLOAT    CFLOAT;
typedef const FLOAT *  PCFLOAT;

typedef double         DOUBLE;
typedef DOUBLE *       PDOUBLE;
typedef const DOUBLE   CDOUBLE;
typedef const DOUBLE * PCDOUBLE;

typedef unsigned char  UCHAR;
typedef UCHAR *        PUCHAR;
typedef const UCHAR    CUCHAR;
typedef const UCHAR *  PCUCHAR;

typedef unsigned int   UINT;
typedef UINT *         PUINT;
typedef const UINT     CUINT;
typedef const UINT *   PCUINT;

typedef unsigned short USHORT;
typedef USHORT *       PUSHORT;
typedef const USHORT   CUSHORT;
typedef const USHORT * PCUSHORT;

typedef unsigned long  ULONG;
typedef ULONG *        PULONG;
typedef const ULONG    CULONG;
typedef const ULONG *  PCULONG;

typedef int            BOOL;
typedef BOOL *         PBOOL;
typedef const BOOL     CBOOL;
typedef const BOOL *   PCBOOL;

typedef char           STR;
typedef STR *          PSTR;
typedef const STR      CSTR;
typedef const STR *    PCSTR;

typedef unsigned char  BYTE;
typedef BYTE *         PBYTE;
typedef const BYTE     CBYTE;
typedef const BYTE *   PCBYTE;

typedef unsigned short WORD;
typedef WORD *         PWORD;
typedef const WORD     CWORD;
typedef const WORD *   PCWORD;

typedef int            RESULT;
typedef RESULT *       PRESULT;
typedef const RESULT   CRESULT;
typedef const RESULT * PCRESULT;

typedef void *         HANDLE;
typedef HANDLE *       PHANDLE;
typedef const HANDLE   CHANDLE;
typedef const HANDLE * PCHANDLE;


static BOOL nAlarmFlag = BOOLFALSE;			/* 警报标志	*/
static struct sigaction struOldAct;			/* 信号处理器 */

/*	

 * 处理SIGALRM 信号
 */
static VOID CatchAlarm(int sig)
{
    if(sig == SIGALRM)
        nAlarmFlag = BOOLTRUE;
}

/*	
 *	安装SIGALRM信号处理函数 
 */
static RESULT InitCatchAlarm()
{ 

    struct sigaction struAct;

    struAct.sa_handler = CatchAlarm;
    struAct.sa_flags = 0;
    sigemptyset(&struAct.sa_mask);
    if(sigaction(SIGALRM, &struAct, &struOldAct) == -1)
    {

        printf( "sigaction 安装信号处理函数错误 /n/t错误代码 = [%d] /
                错误信息 = [%s]/n", errno, strerror(errno));
        return EXCEPTION;
    }
    return NORMAL;
}

/*

 * 	恢复SIGALRM 处理函数
 */
static RESULT EndCatchAlarm()
{
    if(sigaction(SIGALRM, &struOldAct, NULL) == -1)
    {
        printf("sigaction 恢复信号处理函数错误 /n/t错误代码 = [%d] /

                错误信息 = [%s]/n", errno, strerror(errno));
        return EXCEPTION;
    }	
    return NORMAL; 
}

/*
 * 安装定时器
 */
static RESULT InitAlarm(INT nTimerSec)
{

    struct itimerval struValue;

    if(nTimerSec < 0)
    {
        printf( "安装定时器时间太小错误 %d/n", nTimerSec);
        return INVALID;
    }
    struValue.it_value.tv_sec = nTimerSec;

    struValue.it_value.tv_usec = 0;
    struValue.it_interval = struValue.it_value;

    if(setitimer(ITIMER_REAL, &struValue, NULL) == -1)
    {
        printf( "setitimer 安装定时器错误 /n/t错误代码 = [%d] 错误信息 =[%s]/n",

                errno,strerror(errno));
        return EXCEPTION;
    }

    return NORMAL;
}



/**
 * @函数说明:创建到服务器的连接
 * 		@pszHostString:		要连接的主机名称
 * 		@nPort:		要连接的主机端口
 * 		@nTimeout:		超时的秒数.小于0使用超时时间为60

 * @返回说明:	成功返回 连接好的套接字 失败返回 -1
 */ 
INT CreateConnectSocket(PCSTR pszHostString, UINT nPort, UINT nTimeout)
{
    INT nConnectFd;
    struct sockaddr_in struInAddr;

    struct hostent * pstruHost;
    INT nErrorNo;

    nAlarmFlag = BOOLFALSE;
    if(InitCatchAlarm() == EXCEPTION)
    {
        printf(  "InitCatchAlarm 初始化信号操作错误/n");

        return -1;
    }

    nTimeout = nTimeout > 0 ? nTimeout : DEF_COM_TIMEOUT;
    if(InitAlarm(nTimeout) == EXCEPTION)
    {
        printf( "InitAlarm 初始化定时器错误/n");

        EndCatchAlarm();
        InitAlarm(0);
        return -1;
    }

    memset(&struInAddr,0,sizeof(struInAddr));
    if((inet_aton(pszHostString, (struct in_addr *)&struInAddr.sin_addr)) == 0)
    {
        if((pstruHost = gethostbyname(pszHostString)) == NULL)

        {
            printf( 
                    "获取服务器IP地址错误!/n/t错误代码=[%d] 错误信息=[%s]/n",
                    h_errno,hstrerror(h_errno));	
            EndCatchAlarm();
            InitAlarm(0);
            return -1;
        }
        struInAddr.sin_addr = *(struct in_addr *)pstruHost->h_addr_list[0];

    }
    struInAddr.sin_family = AF_INET;
    struInAddr.sin_port = htons(nPort);

    nConnectFd = socket(AF_INET, SOCK_STREAM, 0);
    if(nConnectFd == -1)
    {
        nErrorNo = errno;

        printf( 
                "socket 错误!/n/t错误代码=[%d] 错误信息=[%s]/n",
                errno,strerror(errno));
        EndCatchAlarm();
        InitAlarm(0);
        errno = nErrorNo;
        return -1;
    }	

    if(connect(nConnectFd, (struct sockaddr *)&struInAddr, /

                sizeof(struct sockaddr)) == -1)
    {
        nErrorNo = errno;
        printf( 
                "connect 错误! 错误代码=[%d] 错误信息=[%s]/n",
                errno, strerror(errno));

        close(nConnectFd);
        EndCatchAlarm();
        InitAlarm(0);
        errno = nErrorNo;
        return EXCEPTION;
    }
    EndCatchAlarm();
    InitAlarm(0);

    return(nConnectFd);
}


/**
 *	@函数说明:无同步字符从Socket接收数据
 *	@nConnectFd:			连接的文件描述符
 *	@pszRecvBuffer:	    	接收缓冲区

 *	@nRecvBufferLen:		要接收的长度
 *	@nTimeout:	        	超时时间(秒),如果为0则采用缺省的超时时间60
 *	@返回说明:              成功返回NORMAL 失败返回EXCEPTION
 */
RESULT RecvSocketNoSync(INT nConnectFd, PSTR pszRecvBuffer, /
        UINT nRecvBufferLen, UINT nTimeout)
{

    INT nReadLenth;
    PSTR pszRecvBufferTemp;
    INT nErrorNo;

    nAlarmFlag = BOOLFALSE;
    if(InitCatchAlarm() == EXCEPTION)
    {
        printf(  "InitCatchAlarm 初始化信号操作错误/n");

        return EXCEPTION;
    }

    nTimeout = nTimeout > 0 ? nTimeout : DEF_COM_TIMEOUT;
    if(InitAlarm(nTimeout) == EXCEPTION)
    {
        printf(  "InitAlarm 初始化定时器错误/n");

        EndCatchAlarm();
        InitAlarm(0);
        return EXCEPTION;
    }

    pszRecvBufferTemp = pszRecvBuffer;
    while(nRecvBufferLen > 0)
    {
        nReadLenth = read(nConnectFd, pszRecvBufferTemp, nRecvBufferLen);
        if((nReadLenth < 0) && (errno == EINTR))

        {
            if(nAlarmFlag == BOOLTRUE)
            {
                printf( "RecvSocketNoSync 读取数据超时错误/n");
                EndCatchAlarm();
                InitAlarm(0);
                errno = ETIMEDOUT;
                return EXCEPTION;
            }

            nReadLenth = 0;
        }	
        else if((nReadLenth <0) && (errno != EINTR))
        {
            nErrorNo = errno;
            printf( 
                    "RecvSocketNoSync 读取数据错误/n/t /

                    错误代码 = [%d] 错误信息 = [%s]/n",
                    errno,strerror(errno));
            EndCatchAlarm();
            InitAlarm(0);
            errno = nErrorNo;
            return EXCEPTION;
        }
        else if(nReadLenth == 0)

        {
            printf( "RecvSocketNoSync 读取数据错误 连接被关闭/n");
            EndCatchAlarm();
            InitAlarm(0);
            errno = EIO;
            return EXCEPTION;
        }	
        nRecvBufferLen -= nReadLenth;

        pszRecvBufferTemp += nReadLenth;
    }
    EndCatchAlarm();
    InitAlarm(0);
    return NORMAL;
}

/**
 *	    @函数说明:无同步字符从Socket发送报文
 *		@nConnectFd: 	连接的文件描述符
 *		@pszSendBuffer:		发送缓冲区
 *		@nSendBufferLenth:		要发送的报文长度
 *		@nTimeout:	超时时间(秒),如果小于0则采用系统缺省的超时时间60秒
 *	    @返回说明: 成功返回NORMAL 失败返回EXCEPTION

 */
RESULT SendSocketNoSync(INT nConnectFd, PSTR pszSendBuffer, /
						UINT nSendBufferLenth, UINT nTimeout)
{
	INT nWritenLenth;
	PSTR pszSendBufferTemp;
	INT nErrorNo;

	if(InitCatchAlarm() == EXCEPTION)
	{
		printf( "InitCatchAlarm 初始化信号处理函数错误/n");
		return EXCEPTION;
	}

	nTimeout = nTimeout > 0 ? nTimeout : DEF_COM_TIMEOUT;
	if(InitAlarm(nTimeout) == EXCEPTION)
	{
		printf( "InitAlarm 初始化定时器错误/n");
		EndCatchAlarm();
		InitAlarm(0);
		return EXCEPTION;
	}

	pszSendBufferTemp = pszSendBuffer;
	while(nSendBufferLenth > 0)
	{
		nWritenLenth = write(nConnectFd, pszSendBufferTemp, nSendBufferLenth);
		if((nWritenLenth < 0) && (errno == EINTR))
		{
			if(nAlarmFlag == BOOLTRUE)
			{
				printf( "SendSocketNoSync 发送数据失败 超时/n");
				EndCatchAlarm();
				InitAlarm(0);
				errno = ETIMEDOUT;
				return EXCEPTION;
			}
			nWritenLenth = 0;
		}
		else if((nWritenLenth < 0) && (errno != EINTR))
		{
			nErrorNo = errno;
			printf( "SendSocketNoSync 发送数据到失败 /n/t 错误代码=[%d] /
				错误信息=[%s]/n", errno, strerror(errno));
			EndCatchAlarm();
			InitAlarm(0);
			errno = nErrorNo;
			return EXCEPTION;
		}
		nSendBufferLenth -= nWritenLenth;
		pszSendBufferTemp += nSendBufferLenth;
	}
	EndCatchAlarm();
	InitAlarm(0);
	return NORMAL;
}



int main()
{

    int port,head,timeout,fd;
    char IP[20], filename[20];
  	char buffer[4096],szTemp[5];
	int len,rfd;

    strcpy(IP,"127.0.0.1");
    port=9734;
    timeout=60;
   strcpy(filename,"./aa.txt");


    /*判断要传送的文件是否存在*/
    if (access(filename, F_OK) == -1)
    {
        fprintf(stderr," 打开文件不存在。/n" );
        return(-1);
    }

    /*打开要传的文件*/
    memset(buffer,0,sizeof(buffer));
    if((rfd = open(filename,O_RDONLY)) == -1)

    {
        fprintf(stderr,"打开文件 %s 错误 [%s]/n",filename,strerror(errno));
        return(-1);
    }
    if((len = read(rfd,buffer,sizeof(buffer))) < 1)
    {
        fprintf(stderr,"读取文件错误[%s]/n",strerror(errno));

        return(-1);
    }
    if(buffer[len - 1] == '/n')
        buffer[len - 1] =0;
    close(rfd);

    /*创建套接字和连接*/
    if((fd = CreateConnectSocket(IP,port,timeout)) == -1)

    {
        fprintf(stderr, "建立SOCKET 连接出错!");
        return(-1);
    } 

    /*发送数据*/
    sprintf(szTemp, "%04d", len);
    if(SendSocketNoSync(fd,szTemp,4,timeout) == -1)

        return(-1);	
    if(SendSocketNoSync(fd,buffer,len,timeout) == -1)
        return(-1);	

    /*接收数据*/
    memset(szTemp, 0, sizeof(szTemp));
    memset(buffer, 0, sizeof(buffer));

    if(RecvSocketNoSync(fd,szTemp,4,timeout) == -1)
        return(-1);
    if(RecvSocketNoSync(fd,buffer,atoi(szTemp),timeout) == -1)

        return(-1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值