- 论坛徽章:
- 0
|
简单事务协议(Trivial Transaction Protocol)
我觉得unix程序员中有一个矛盾,写unix程序有很多情况都是要用到网络通讯的,但是很多unix程序员对socket实现不甚了解,而那些做交换机和路由器的人,又对unix不甚了解,我认识的搞路由器设计的人甚至都大会用数据库,真是隔行如隔山。
上面写的那篇文章是我在看了rfc 955之后写的,要说有什么意义,意义也真不怎么大,据我的测试,在联机事务处理中,采用这个协议,要比使用tcp套接字快10倍,而且没有什么诸如fin_wait_2之类的现象,但这又能如何?只能算是自娱自乐罢了。
下面是这个协议的客户端实现,也没什么高深的知识,我个人水平也很一般,也写不出什么高深的东西来,感兴趣的可以看一看。服务器端比较简单,我就不写了。
[code]/********************************************************************************************************
联机事务处理客户端程序
说明:uint16_t表示无符号16位整数,一般对应于unsigned short类型
这个实现要求套接字功能中的setsockopt()设置超时时间,在某些系统中,比如sco unix,早期版本的linux可能不支持,
需要用设置SIGALM信号处理函数的方式来解决
本程序在IBM AIX4.3下调试通过
*********************************************************************************************************/
#include <stdlib.h>;
#include <time.h>;
#include <sys/time.h>;
#include <sys/socket.h>;
#include <arpa/inet.h>;
#include <netinet/in.h>;
#define REPEATTIME 3
#define TRUE 1
#define FALSE 0
#define LOGINRTO 10
#define HEADLEN 6
#define MAXDATALEN 4096
static int clisock;
static int svrsock;
static struct sockaddr_in cliaddr;
static struct sockaddr_in svraddr;
static struct sockaddr_in svraddr2;
static unsigned char sphead[HEADLEN];
/********************************************************************************************************
登陆函数
输入参数:客户代号(16位无符号整数),初始事务号(16位无符号整数)
客户端地址("xxx.xxx.xxx.xxx"),客户端端口号(16位无符号整数)
服务端地址("xxx.xxx.xxx.xxx"),服务端端口号(16位无符号整数)
要求输入参数为主机字节顺序
输出参数:1为成功,0为失败,错误信息保存在errno里
本函数修改了全局静态变量,是不可重入函数
********************************************************************************************************/
int login(uint16_t curid, uint16_t isn, const char * cliaddrs, uint16_t cliport, const char * svraddrs, uint16_t svrport)
{
int i;
struct timeval loginrto;
int connected;
int answered;
int recvlen;
int time1,time2;
unsigned char answer[HEADLEN];
connected=FALSE;
clisock=socket(AF_INET,SOCK_DGRAM,0);
if(clisock>;0)
{
cliaddr.sin_family=AF_INET;
cliaddr.sin_port=htons(cliport);
cliaddr.sin_addr.s_addr=inet_addr(cliaddrs);
if(bind(clisock,(struct sockaddr *)&cliaddr,sizeof(cliaddr))==0)
{
sphead[0]=0x80;
*((uint16_t *)(sphead+1))=htons(curid);
*((uint16_t *)(sphead+3))=htons(isn);
sphead[5]=0;
svraddr.sin_family=AF_INET;
svraddr.sin_port=htons(svrport);
svraddr.sin_addr.s_addr=inet_addr(svraddrs);
i=0;
loginrto.tv_sec=LOGINRTO;
loginrto.tv_usec=0;
answered=FALSE;
/**** 接受应答循环,如果发来的是杂包则丢弃*/
while((i<REPEATTIME) && !answered)
{
sendto(clisock,sphead,sizeof(sphead),0,(struct sockaddr *)&svraddr,sizeof(svraddr));
setsockopt(clisock,SOL_SOCKET,SO_RCVTIMEO,&loginrto,sizeof(loginrto));
time(&time1);
recvlen=recvfrom(clisock,answer,sizeof(answer),0,NULL,NULL);
if((recvlen==sizeof(answer)) && (memcmp(answer+1,sphead+1,5)==0))/*是针对本次的应答包*/
{
answered=TRUE;
if(answer[0]==sphead[0])
connected=TRUE;/*还有一种可能是answer[0]==0xC0,服务端拒绝了客户的连接*/
}
else
if(recvlen<0)/*接收失败*/
{
i++;
loginrto.tv_sec=loginrto.tv_sec<<2;
}
else/*接收到了上次的包*/
{
time(&time2);
loginrto.tv_sec=loginrto.tv_sec-(time2-time1);
}
}/*end of while*/
}/*end of bind()==0 */
}
return connected;
}
/********************************************************************************************************
开始一个事务
********************************************************************************************************/
void beginsection(void)
{
sphead[0]=0;
sphead[3]++;
sphead[4]=sphead[4]+(sphead[3]==0);
sphead[5]=0;
svraddr2=svraddr;
}
/********************************************************************************************************
退出函数
并不返回结果
********************************************************************************************************/
int logout(void)
{
int i;
int answered,disconnected;
struct timeval logoutrto;
int recvlen,time1,time2;
unsigned char answer[HEADLEN];
/*事务号加一*/
beginsection();
/*结束连接标志置位*/
sphead[0]=0x20;
logoutrto.tv_sec=LOGINRTO;
logoutrto.tv_usec=0;
i=0;
answered=FALSE;
disconnected=FALSE;
/**** 接受应答循环,如果发来的是杂包则丢弃*/
while((i<REPEATTIME) && !answered)
{
sendto(clisock,sphead,sizeof(sphead),0,(struct sockaddr *)&svraddr,sizeof(svraddr));
setsockopt(clisock,SOL_SOCKET,SO_RCVTIMEO,&logoutrto,sizeof(logoutrto));
time(&time1);
recvlen=recvfrom(clisock,answer,sizeof(answer),0,NULL,NULL);
if((recvlen==sizeof(answer)) && (memcmp(answer+1,sphead+1,5)==0))/*是针对本次的应答包*/
{
answered=TRUE;
if(answer[0]==sphead[0])
disconnected=TRUE;
}
else
if(recvlen<0)/*接受失败*/
{
i++;
logoutrto.tv_sec=logoutrto.tv_sec<<1;
}
else/*接收到了上次的包*/
{
time(&time2);
logoutrto.tv_sec=logoutrto.tv_sec-(time2-time1);
}
}/*end of while*/
close(clisock);
return disconnected;
}
int sendandrecv(const char * sendbuff,int sendsize, char * recvbuff, int recvsize)
{
char sendbuff2[HEADLEN+MAXDATALEN];
char recvbuff2[HEADLEN+MAXDATALEN];
static unsigned int rtoa=6;/*平滑时间估计器*/
static unsigned int rtod=1;/*标准偏差时间估计器*/
static struct timeval rto;/*时间估计器*/
int time1,time2,timem;
int i;
int answered;
int returnlen;
size_t fromlen;
memcpy(sendbuff2,sphead,sizeof(sphead));
memcpy(sendbuff2+sizeof(sphead),sendbuff,sendsize);
rto.tv_sec=rtoa+rtod<<2;
rto.tv_usec=0;
answered=FALSE;
i=0;
fromlen=sizeof(svraddr2);
while((i<REPEATTIME)&& !answered)
{
sendto(clisock,sendbuff2,sizeof(sphead)+sendsize,0,(struct sockaddr *)&svraddr,sizeof(svraddr));
setsockopt(clisock,SOL_SOCKET,SO_RCVTIMEO,&rto,sizeof(rto));
time(&time1);
returnlen=recvfrom(clisock,recvbuff2,sizeof(sphead)+recvsize,0,(struct sockaddr *)&svraddr2,&fromlen)-sizeof(sphead);
time(&time2);
timem=time2-time1;
if((returnlen>;0)&& (memcmp(recvbuff2+1,sphead+1,5)==0))/*接收到本次的返回包*/
{
answered=TRUE;
rtod=rtod+(abs(timem-rtoa)-rtod)>;>;2;
rtoa=rtoa+(timem-rtoa)>;>;3;
sphead[5]++;
}
else
if((returnlen==0)&&(recvbuff2[0]==0x20))/*收到复位标志*/
answered=TRUE;
else
if(returnlen<0)/*接收失败*/
{
i++;
rto.tv_sec=rto.tv_sec<<1;
}
else/*接受的不是本次的包*/
rto.tv_sec=rto.tv_sec-timem;
}
return returnlen;
}
int main(void)
{
return 0;
}[/code] |
|