Chinaunix首页 | 论坛 | 博客
  • 博客访问: 47705
  • 博文数量: 26
  • 博客积分: 586
  • 博客等级: 中士
  • 技术积分: 230
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-08 20:10
文章分类
文章存档

2012年(6)

2011年(20)

我的朋友

分类: 网络与安全

2011-04-18 20:28:41

基本函数定义

 

1.Static void proc_sessions(int tid,int p);//udp队列处理定时器函数

 

2.static void proc_session(soc_session_t *session);//处理会话函数

 

3.static int soc_mod_init_func(void)//udp模块入口函数()

 

4.static int soc_mod_fina_func(void)//udp模块出口函数()

 

5. int ms_bearer_open(int mode, void * cb)//开打设备函数

*cb为相关回调函数  定义 typedef void(*ms_bearer_cb_t)(int event)

 

6.void bearer_cb_action();//open函数的回调函数(demo中实现.c中不出现)

 

7. int ms_bearer_close()//关闭设备函数

 

8. void * _vm_soc_session_malloc()//开辟会话session

 

9. void _ms_soc_session_free(int handle)//释放会话session

 

10. void * _ms_soc_session_get(int handle)//根据

 

11. int ms_soc_create_udp(int type, void * cb)//创建套接字 type0udp

       底下调用的是

12. int ms_soc_close(int s)//关闭套接字

 

13. int ms_soc_sendto(int s,const void *buf,int len,ms_sockaddr *addr)//udp发送函数

session = _ms_soc_session_get(s)

底下调用nwrite = sendto(sessions[handle].socket, (char*)buf, len, 0,(struct sockaddr*)&remote_udp,sizeof(remote_udp));

 

14. int ms_soc_recvfrom(int s,void *buf,int len,ms_sockaddr *addr)//udp接收函数

底下调用的是

nread = recvfrom(sessions[handle].socket, (char*)buf, len, 0,(struct sockaddr*)&remote_udp,&serverlen);

 

15. int ms_inet_addr(char * ipchar, uint8 * ip)

"xxx.xxx.xxx.xxx"格式的IP地址字符串转换为4字节整型

uint32 ipp = inet_addr(ipchar);

       if (ip)

              memcpy(ip, &ipp, 4);

16 void get_host_timer_cb(int tid, int p)

 

17. int ms_soc_gethostbyname(int s, const char * host, void * cb)

session = (soc_session_t*)_ms_soc_session_get(s);

 

大体思路如下:

Int ms_init(void)//demo中主函数入口

{

(一)Ms_soc_init()-à

1(soc_mod_init_func()àret = WSAStartup(MAKEWORD(1, 1), &ws);// 初始化Windows Socket库。

2ms_quick_timer(1000,0, proc_sessions,1);打开定时器每隔一秒调用proc_sessions函数,if (sessions[i].used)如果有会话再调用proc_session(sessions + i)函数)

(二)bearer_open_action()à

1. ret=int ms_bearer_open(int mode, void * cb) //正在打开网络设备接口

(void*)bearer_cb_action根据ret返回值执行,ret值多为-2所以调用

void bearer_cb_action(int event)

提示"1键开始创建套接字连接");如果按1  进入按键事件函数

void key_event_up(int param0)

switch(param0)  case MS_KEY_NUM1     :soc_create_action();开始创建套接字

 

}

 

一些基本内部变量声明

typedef struct _soc_session_t {

       int used;

       int handle;

       SOCKET socket;

       enum {UDP_CONNECTING, UDP_CONNECTED, UDP_WAIT_CLOSE} udp_state;

       enum {BLOCK_WRITE, CAN_WRITE} write_pipe;

       enum {BLOCK_READ, CAN_READ} read_pipe;

       //void (*hook)(int handler, int state);

 

       ms_sockaddr addr;

    // typedef struct _ms_sockaddr

{uint16   port;             /* 端口号 */

uint8     addr[14];      /* IP地址,通常为4字节;为兼容BSD标准,此处为14

} ms_sockaddr;

      

ms_get_host_cb_t get_host_cb;

//函数指针 typedef void (*ms_get_host_cb_t)(int s,int ip)

      

ms_soc_cb_t soc_cb;

//函数指针 typedef int(*ms_soc_cb_t)(int s,int e)

} soc_session_t;

//附:就是enum tcp_state改成udp_state

 

2. #define MS_SOCEVT_CONNECT             (1)

/* 套接字可写 */

#define MS_SOCEVT_WRITE                (2)

/* 套接字可读 */

#define MS_SOCEVT_READ                         (3)

/* 套接字被关闭 */

#define MS_SOCEVT_CLOSE                (4)

/* 套接字连接失败 */

#define MS_SOCEVT_CONNECT_FAILED     (5)

/////////////////////////////////////////////////////////////////////////

一些关键地方说明

(一)  创建注册说明

 

1.int ms_soc_create_udp(int type, void * cb)

       soc_session_t* session;

*cb=soc_cb_action()

       //进行相关的准备

       session = _vm_soc_session_malloc()

              unsigned long ul = 1;

              unsigned long p = 0;

 

              session->udp_state = UDP_CONNECTED;//

/////////////////////////////////////////////////////////////////////////////////////

重点说明:如果创建成功则一秒以后定时器刷函数    void proc_sessions(int tid, int p)根据soc_session_t* session结构体中

session->udp_state的值自动进入函数void proc_session(soc_session_t* session) case _CONNECTED:调用

session->soc_cb(session->handle, MS_SOCEVT_CONNECT_FAILED)

也就是void soc_cb_action(int s, int e)根据e的不同执行

case MS_SOCEVT_WRITE:

             soc_send_action(s);            //开始发送数据

      case MS_SOCEVT_READ:

             soc_recv_action(s);            //开始接收数据

/////////////////////////////////////////////////////////////////////////////

              session->used = TRUE;//

              session->soc_cb = cb;//把地址接到session会话中

//定义函数指针 将来传递(void*)soc_cb_action执行sendtorecvfrom

             

              if ((session->socket = socket(PF_INET, type, 0)) == INVALID_SOCKET)

                     _ms_soc_session_free(session->handle);

             

       1.    if(ioctlsocket(session->socket, FIONBIO, (unsigned long*)&ul) == SOCKET_ERROR)//控制套接口的模式

       2.    if (ioctlsocket(session->socket, FIONREAD, &p) != 0)

              return session->handle

 

 

(二)客户端回调函数

//int soc_create_actionàs = ms_soc_create(0, (void*)soc_cb_action)注册

因为定时器每过一秒就调用一次void proc_sessions(int tid,int p)àvoid proc_session(soc_session_t *session)通过传递过来的结构体判断会话中session->udp_state的值

case TCP_CONNECTING  àcase TCP_CONNECTED  àcase TCP_WAIT_CLOSE

Sessionàudp_state 进而调用函数void soc_cb_action(int s, int e)

 

Ret=select(1, NULL, &fdwrs, NULL, &timeout)à FD_ISSET(session->socket, &fdwrs)

根据select的返回值和isset判断sd句柄是否在相对应文件描述符中其中

(1).session->soc_cb(session->handle, MS_SOCEVT_CONNECT_FAILED);

(2). session->soc_cb(session->handle, MS_SOCEVT_CONNECT);

{

       switch (e)

       {

       case MS_SOCEVT_CONNECT:

       case MS_SOCEVT_WRITE:

              soc_send_action(s);             //开始发送数据

              break;

       case MS_SOCEVT_READ:

              soc_recv_action(s);             //开始接收数据

              break;

       case MS_SOCEVT_CLOSE:

       case MS_SOCEVT_CONNECT_FAILED:

              break;                         //错误处理或重连接               

       }

}

 

(三)select端回调函数

用法说明:

select()函数,这个函数允许我们执行I/O多路转接。其具体含义就是select()函数可以构造一个表,在这个表中包含了我们所有要用到的文件描述符。然后我们可以调用一个函数,这个函数可以检测这些文件描述符的状态,当某个(我们指定的)文件描述符准备好进行I/O操作时,此函数就返回,告知进程哪个文件描述符已经可以执行I/O操作了。这样就避免了长时间的阻塞。

因为这个函数下边几个函数中多次用到

void proc_session(soc_session_t* session)

int ms_soc_sendto(int s,const void *buf,int len,ms_sockaddr *addr)

int ms_soc_recvfrom(int s,void *buf,int len,ms_sockaddr *addr)

特别说明的是他的最后一个参数 timeout 参数timeout的设置有三种情况。

1.timeout==NULL时,这表示用户希望永远等待,直到我们指定的文件描述符中的一个已准备好,或者是捕捉到一个信号。如果是由于捕捉到信号而中断了这个无限期的等待过程的话,select()将返回"-1",同时设置errno的值为 EINTR

2.timeout->tv_sec==0&&timeout->tv_usec==0,那么这表示完全不等待。 Select()测试了所有指定文件描述符后立即返回。这是得到多个描述符状态而不阻塞select()函数的轮询方法。

3..timeout->tv_sec=0||timeout->tv_usec=0,那么这两个参数的值即为我们希望函数等待的时间。其中tv_sec设置时间单位为秒,tv_usec设置时间单位为微秒。如果在超时的时候,在我们指定的所有文件描述符里面仍然没有任何一个准备好的话,则select()将返回"0"

Int select(int n, fd_set *readfds, fd_set *writefds, fd_est *exceptfds, struct timeval *timeout);
FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);

}

 

()一次读写数据整个过程中会话以及对应的函数调用变化情况sendto   recvfrom(send /recv)

1int ms_soc_recv(int s, void * buf, int len)

通过v=select(1, &fdwrs, NULL, NULL, &timeout)返回值v看下 读文件描述符中是否有 当v大于0的时候进行循环读取,如果等于-1进行出错误处理

如果没有v返回0   返回MS_SOC_WAIT;再次等待

一般情况下会不断刷函数void proc_session(soc_session_t* session)

case TCP_CONNECTED:因为v一直为0不满足条件if (v > 0 && FD_ISSET(session->socket, &fdwrs))所以总是break退出

直到再次有数据到来执行函数session->soc_cb(session->handle, MS_SOCEVT_READ);à

阅读(784) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~