You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

912 lines
23 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*****************************************************************************
* FileName : netport.c *
* Programmer : Li Liangchu *
* Writen at : 2004.07.21 *
* Version : *
* Description: base on net comm sports driver *
* Last modify: 2004.07.21 *
*****************************************************************************/
//#include "serialport.h"
#include "netport.h"
#include "commport.h"
#include "common.h"
#ifndef _WIN32
#include <sys/ioctl.h>
#endif
int netWSAStartupErr = FALSE;
extern SIO_PARAM_DEF SioParam[];
extern u_short MaxSerialPortNum;
extern u_short MaxNetPortNum;
extern u_short MaxPortNum;
//创建 UDP 通讯 socket
BYTE CreateUdpSock(int *CommSock, DWORD NetPort, DWORD NetCommIpAddr)
{
int tmp, retval;
struct sockaddr_in addr;
u_long largp = 1L; //非阻塞模式
char tmp_buf[256];
if(*CommSock > -1)
return SOCKET_BEING;
if((NetPort == 0) && (NetCommIpAddr == 0))
return FAIL_GREATE;
*CommSock = socket(AF_INET, SOCK_DGRAM, 0);
if(*CommSock < 0)
{
*CommSock = -1;
return FAIL_GREATE;
}
// 将socket设置为非阻塞模式
#ifdef OS_UNIX
tmp = fcntl(*CommSock, F_GETFL, 0);
fcntl(*CommSock, F_SETFL, tmp|O_NONBLOCK);
#else
retval = ioctlsocket(*CommSock, FIONBIO, (u_long FAR *)&largp);
#endif
if (SOCKET_ERROR == retval)
{
// retval = WSAGetLastError();
// sprintf(tmp_buf, "ioctlsocket设置非阻塞模式错误, SocketError=%d, SocketId = %d", retval, *CommSock);
// DebugPrint(tmp_buf);
closesocket(*CommSock);
*CommSock = -1;
return FAIL_GREATE;
}
//设置socket输入输出缓冲
tmp = MAX_NET_BUF_SIZE;
setsockopt(*CommSock, SOL_SOCKET, SO_RCVBUF, (char*)&tmp, sizeof(tmp));
tmp = MAX_NET_BUF_SIZE;
setsockopt(*CommSock, SOL_SOCKET, SO_SNDBUF, (char*)&tmp, sizeof(tmp));
tmp = 1;
setsockopt(*CommSock, SOL_SOCKET, SO_KEEPALIVE, (char*)&tmp, sizeof(tmp));
setsockopt(*CommSock, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, sizeof(tmp));
// 增加udp广播通讯(广播地址)
if((NetCommIpAddr & 0x000000FF) == 0x000000FF)
{
setsockopt(*CommSock, SOL_SOCKET, SO_BROADCAST, (char*)&tmp, sizeof(tmp));
}
//让配置socket 能收不同网段的配置命令
//bzero(&addr, sizeof(addr));
memset((char*)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(NetPort);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(*CommSock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
closesocket(*CommSock);
*CommSock = -1;
return FAIL_GREATE;
}
return SUCCEED_GREATE;
}
//创建 TCP Server socket
BYTE CreateTcpServerSock(int *LiSock, DWORD NetPort)
{
int i, tmp, ret, retval;
#ifdef _WIN32
int len;
#else
socklen_t len;
#endif
int keep_alive = 1; // 设定KeepAlive
int keep_idle = 5; // 开始首次KeepAlive探测前的TCP空闭时间(s)
int keep_interval = 3; // 两次KeepAlive探测间的时间间隔(s)
int keep_count = 3; // 判定断开前的KeepAlive探测次数
struct sockaddr_in addr;
u_long largp = 1L; //非阻塞模式
char tmp_buf[256];
if(-1 < *LiSock)
return SOCKET_BEING;
if(NetPort == 0)
return FAIL_GREATE;
*LiSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//len = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//*LiSock = len;
if(*LiSock < 0)
{
// retval = WSAGetLastError();
// sprintf(tmp_buf, "ioctlsocket设置非阻塞模式错误, SocketError=%d, SocketId = %d", retval, *LiSock);
*LiSock = -1;
return FAIL_GREATE;
}
// 将socket设置为非阻塞模式
#ifdef OS_UNIX
tmp = fcntl(*LiSock, F_GETFL, 0);
fcntl(*LiSock, F_SETFL, tmp|O_NONBLOCK);
#else
retval = ioctlsocket(*LiSock, FIONBIO, (u_long FAR*)&largp);
#endif
if (SOCKET_ERROR == retval)
{
// retval = WSAGetLastError();
// sprintf(tmp_buf, "ioctlsocket设置非阻塞模式错误, SocketError=%d, SocketId = %d", retval, *LiSock);
// DebugPrint(tmp_buf);
closesocket(*LiSock);
*LiSock = -1;
return FAIL_GREATE;
}
///设置socket的输入输出缓冲区大小
tmp = MAX_NET_BUF_SIZE;
setsockopt(*LiSock, SOL_SOCKET, SO_RCVBUF, (char*)&tmp, sizeof(tmp));
tmp = MAX_NET_BUF_SIZE;
setsockopt(*LiSock, SOL_SOCKET, SO_SNDBUF, (char*)&tmp, sizeof(tmp));
len = 4;
tmp_buf[0] = 1;
tmp = setsockopt(*LiSock, SOL_SOCKET, SO_KEEPALIVE, tmp_buf, len);
tmp = getsockopt(*LiSock, SOL_SOCKET, SO_KEEPALIVE, tmp_buf, &len);
tmp = 1;
// setsockopt(*LiSock, SOL_SOCKET, SO_KEEPALIVE, (char*)&tmp, sizeof(tmp));
setsockopt(*LiSock, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, sizeof(tmp));
//set_keepalive(*LiSock, keep_alive, keep_idle, keep_interval, keep_count);
//让TCP接收所有连线
memset((char*)&addr,0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(NetPort);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
//printf("TIP_(%04d): Port = %d, NetCommIpAddr(%08x), addr.sin_addr.s_addr(%08x)\n", getpid(), commid+1, *NetCommIpAddr, addr.sin_addr.s_addr);
if(bind(*LiSock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
//printf("errno = %d\n", errno);
//close(*LiSock);
closesocket(*LiSock);
*LiSock = -1;
return FAIL_GREATE;
}
//printf("succeed!\n");
ret = listen(*LiSock, 4);
if(ret < 0)
{
//close(*LiSock);
closesocket(*LiSock);
*LiSock = -1;
return FAIL_GREATE;
}
return SUCCEED_GREATE;
}
//创建 TCP Client socket
BYTE CreateTcpClientSock(int *CommSock, DWORD NetPort, DWORD NetCommIpAddr)
{
int tmp;
#ifdef _WIN32
int len;
#else
socklen_t len;
#endif
int keep_alive = 1; // 设定KeepAlive
int keep_idle = 5; // 开始首次KeepAlive探测前的TCP空闭时间
int keep_interval = 3; // 两次KeepAlive探测间的时间间隔
int keep_count = 3; // 判定断开前的KeepAlive探测次数
struct sockaddr_in addr;
u_long largp = 1L; //非阻塞模式
char tmp_buf[256];
if(-1 < *CommSock)
return SOCKET_BEING;
if((NetPort == 0) && (NetCommIpAddr == 0))
return FAIL_GREATE;
*CommSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(*CommSock < 0)
{
*CommSock = -1;
return FAIL_GREATE;
}
// 将socket设置为非阻塞模式
#ifdef OS_UNIX
tmp = fcntl(*CommSock, F_GETFL, 0);
fcntl(*CommSock, F_SETFL, tmp|O_NONBLOCK);
#else
tmp = ioctlsocket(*CommSock, FIONBIO, (u_long *)&largp);
#endif
if (SOCKET_ERROR == tmp)
{
// tmp = WSAGetLastError();
// sprintf(tmp_buf, "ioctlsocket设置非阻塞模式错误, SocketError=%d, SocketId = %d", tmp, *CommSock);
// DebugPrint(tmp_buf);
closesocket(*CommSock);
*CommSock = -1;
return FAIL_GREATE;
}
///设置socket的输入输出缓冲区大小
tmp = MAX_NET_BUF_SIZE;
setsockopt(*CommSock, SOL_SOCKET, SO_RCVBUF, (char*)&tmp, sizeof(tmp));
tmp = MAX_NET_BUF_SIZE;
setsockopt(*CommSock, SOL_SOCKET, SO_SNDBUF, (char*)&tmp, sizeof(tmp));
len = 4;
tmp_buf[0] = 1;
tmp = setsockopt(*CommSock, SOL_SOCKET, SO_KEEPALIVE, tmp_buf, len);
tmp = getsockopt(*CommSock, SOL_SOCKET, SO_KEEPALIVE, tmp_buf, &len);
tmp = 1;
// setsockopt(*CommSock, SOL_SOCKET, SO_KEEPALIVE, (char*)&tmp, sizeof(tmp));
setsockopt(*CommSock, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, sizeof(tmp));
// set_keepalive(*CommSock, keep_alive, keep_idle, keep_interval, keep_count);
//bzero(&addr, sizeof(addr));
memset((char*)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(NetPort);
addr.sin_addr.s_addr = htonl(NetCommIpAddr);
//printf("TIP_(%04d): Port = %d, connect(%08x)\n", getpid(), commid+1, *NetCommIpAddr);
if(connect(*CommSock, (struct sockaddr *)&addr, sizeof(addr)) != 0)
{
//printf(" connect error errno= %d, EINPROGRESS=%d\n", errno,EINPROGRESS);
if(EINPROGRESS != errno)
{
closesocket(*CommSock);
//printf(" connect error errno= %d, EINPROGRESS=%d\n", errno,EINPROGRESS);
*CommSock = -1;
return FAIL_GREATE;
}
// 非阻塞的情况下不能这样使用
// else
// {
// if(connect(*CommSock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
// {
// //printf(" connect error errno= %d, EISCONN=%d\n", errno,EISCONN);
// if(EISCONN != errno)
// {
// printf(" connect error errno= %d, EISCONN=%d\n", errno,EISCONN);
// close(*CommSock);
// *CommSock = -1;
// return FAIL_GREATE;
// }
// }
// //printf(" connect succeed errno= %d EISCONN=%d\n", errno, EISCONN);
// }
}
return SUCCEED_GREATE;
}
//int keep_alive = 1;//设定KeepAlive
//int keep_idle = 1;//开始首次KeepAlive探测前的TCP空闭时间
//int keep_interval = 1;//两次KeepAlive探测间的时间间隔
//int keep_count = 3;//判定断开前的KeepAlive探测次数
/*void set_keepalive(int fd, int keep_alive, int keep_idle, int keep_interval, int keep_count)
{
if(keep_alive)
{
if(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keep_alive, sizeof(keep_alive)) == -1)
{
fprintf(stderr, "setsockopt SOL_SOCKET::SO_KEEPALIVE failed, %s\n",strerror(errno));
}
if(setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void *)&keep_idle,sizeof(keep_idle)) == -1)
{
fprintf(stderr, "setsockopt SOL_TCP::TCP_KEEPIDLE failed, %s\n", strerror(errno));
}
if(setsockopt(fd,SOL_TCP,TCP_KEEPINTVL, (void *)&keep_interval, sizeof(keep_interval)) == -1)
{
fprintf(stderr, "setsockopt SOL_tcp::TCP_KEEPINTVL failed, %s\n", strerror(errno));
}
if(setsockopt(fd,SOL_TCP,TCP_KEEPCNT, (void *)&keep_count,sizeof(keep_count)) == -1)
{
fprintf(stderr, "setsockopt SOL_TCP::TCP_KEEPCNT failed, %s\n", strerror(errno));
}
}
}*/
void OpenNetPort(int commid)
{
BYTE succeedflag;
int i, commsock;
DWORD netport, netcommipaddr;
commsock = SioParam[commid].CommSock;
netport = SioParam[commid].NetPort;
netcommipaddr = SioParam[commid].NetCommIpAddr;
switch(SioParam[commid].NetType)
{
case UDP_COMM: // UDP 通讯
if(OPEN_PORT == SioParam[commid].OpenFlag)
return;
succeedflag = CreateUdpSock(&commsock, netport, netcommipaddr);
if(SUCCEED_GREATE == succeedflag)
{
SioParam[commid].OpenFlag = OPEN_PORT;
SioParam[commid].CommSock = commsock;
}
break;
case TCP_S_COMM: // TCP 服务器通讯
commsock = SioParam[commid].LiSock;
succeedflag = CreateTcpServerSock(&commsock, netport);
if(SUCCEED_GREATE == succeedflag)
{
for(i=MaxSerialPortNum; i<MaxPortNum; i++)
{
if(TCP_S_COMM == SioParam[i].NetType)
{
if(SioParam[i].NetPort == netport)
{
printf("端口%d netport=%d lisock=%d\n", i+1, netport, commsock);
SioParam[i].LiSock = commsock;
}
}
}
}
break;
case TCP_C_COMM: // TCP 客户通讯
if(OPEN_PORT == SioParam[commid].OpenFlag)
return;
succeedflag = CreateTcpClientSock(&commsock, netport, netcommipaddr);
if(SUCCEED_GREATE == succeedflag)
{
SioParam[commid].CommSock = commsock;
//if(commid == 8)
//printf("端口%d 创建TCP 客户端成功socket=%d\n", commid+1, SioParam[commid].CommSock);
}
break;
}
}
void CloseNetPort(int commid)
{
switch(SioParam[commid].NetType)
{
case UDP_COMM: // UDP 通讯
if(SioParam[commid].CommSock > -1)
closesocket(SioParam[commid].CommSock);
SioParam[commid].CommSock = -1;
if(CLOSE_PORT != SioParam[commid].OpenFlag)
{
SioParam[commid].OpenFlag = CLOSE_PORT;
}
break;
case TCP_S_COMM: // TCP 服务器通讯
if(SioParam[commid].CommSock > -1)
closesocket(SioParam[commid].CommSock);
//printf("关闭端口%d TCP客户端Socket=%d\n", commid+1, SioParam[commid].CommSock);
SioParam[commid].CommSock = -1;
if(CLOSE_PORT != SioParam[commid].OpenFlag)
{
SioParam[commid].OpenFlag = CLOSE_PORT;
}
break;
case TCP_C_COMM: // TCP 客户端通讯
if(SioParam[commid].CommSock > -1)
closesocket(SioParam[commid].CommSock);
SioParam[commid].CommSock = -1;
//printf("关闭端口%d TCP客户端Socket=%d\n", commid+1, SioParam[commid].CommSock);
if(CLOSE_PORT != SioParam[commid].OpenFlag)
{
SioParam[commid].OpenFlag = CLOSE_PORT;
}
break;
}
// 删除所有的发送缓冲区wen 2005.07.27
PortWriteDataFree(commid);
}
// TCP服务器端的侦听socket关闭与打开与端口是否打开的标识(SioParam[commid].OpenFlag)无关
void CloseNetListenPort(int commid)
{
int i;
switch(SioParam[commid].NetType)
{
case TCP_S_COMM: // TCP 服务器通讯
if(SioParam[commid].LiSock > -1)
//close(SioParam[commid].LiSock);
closesocket(SioParam[commid].LiSock);
SioParam[commid].LiSock = -1;
// 使用相同TCP服务端口的端口的listen套接字全部标识为1(关闭)
for(i=MaxSerialPortNum; i<MaxPortNum; i++)
{
if(SioParam[i].LiSock == SioParam[commid].LiSock)
SioParam[i].LiSock = -1;
}
break;
case UDP_COMM: // UDP 通讯
break;
case TCP_C_COMM: // TCP 客户端通讯
break;
}
}
// UDP网络通讯接收数据
void UdpRecv(int commid, int fds, u_long ipaddr)
{
int len;
char revbuf[MAX_MSG_BUF_SIZE];
struct sockaddr_in addr;
#ifdef _WIN32
int addr_len = sizeof(struct sockaddr_in);
#else
socklen_t addr_len = sizeof(struct sockaddr_in);
#endif
// 将该socket中的数据读完
do
{
len = recvfrom(fds, revbuf, MAX_MSG_BUF_SIZE, 0, (struct sockaddr *)&addr, &addr_len);
if(addr.sin_addr.s_addr == ipaddr)
{
if(IsBaoHuPtr(commid))
{
PutDataToBuf(&SioParam[commid].RecvBuf, (u_char*)revbuf, len);
}
}
}while(len >= MAX_MSG_BUF_SIZE);
}
//从头结点往后删
void DelNode(int commid)
{
struct WR_DATA *next;
if (!SioParam[commid].WriteData)
{
return;
}
//SioParam[commid].iWriteDataNo--;
next = SioParam[commid].WriteData->Next;
HEAP_FREE(SioParam[commid].WriteData);
SioParam[commid].WriteData = next;
}
void UdpSend(int commid)
{
int len, plen, slen;
struct sockaddr_in addr;
if(!IsBaoHuPtr(commid))
return;
if(NULL == SioParam[commid].WriteData)
return;
//bzero(&addr, sizeof(addr));
memset((char*)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(SioParam[commid].NetPort);
addr.sin_addr.s_addr = SioParam[commid].NetCommIpAddr;
// 错误判断和断点续传
plen = SioParam[commid].WriteData->PLen;
slen = SioParam[commid].WriteData->MsgLen - plen;
if(slen <= 0)
{
DelNode(commid);
return;
}
len = sendto(SioParam[commid].CommSock,(const char*)&SioParam[commid].WriteData->MsgData[plen], slen,
0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if(len > 0)
{
if(len < slen)
{
if(EINPROGRESS != errno)
{
CloseNetPort(commid);
}
else
{
SioParam[commid].WriteData->PLen += len;
}
}
else
{
DelNode(commid);
}
//ShmAddSendCount(commid, len);
}
else if(EINPROGRESS != errno)
{
CloseNetPort(commid);
}
}
BOOL TcpRecv(int commid, int fds, u_long ipaddr)
{
BOOL bRetVal;
int len, nread;
char revbuf[MAX_MSG_BUF_SIZE];
// if(OPEN_PORT != SioParam[commid].OpenFlag)
// return FALSE;
bRetVal = TRUE;
//删除已断开的子socket
//ioctl(fds, FIONREAD, &nread);
/*if(nread == 0)
{
//if(commid == 8)
// printf("TIP_(%04d): Port=%d Peer Socket is closed already.\n", getpid(), commid+1);
CloseNetPort(commid);
bRetVal = FALSE;
}
else*/
{
do
{
len = recv(fds, revbuf, MAX_MSG_BUF_SIZE, 0);
// 错误判断 len = 0 有可能是对方已经关闭socket
if(len <= 0)
{
printf("port%d read error len=%d\n", commid+1, len);
if(EINPROGRESS != errno)
{
//printf("port%d read error\n", commid+1);
CloseNetPort(commid);
bRetVal = FALSE;
break;
}
}
if(IsBaoHuPtr(commid))
{
PutDataToBuf(&SioParam[commid].RecvBuf, (u_char*)revbuf, len);
}
}while(len >= MAX_MSG_BUF_SIZE);
}
return bRetVal;
}
void TcpSend(int commid)
{
int len, plen, slen;
if(OPEN_PORT != SioParam[commid].OpenFlag)
{
SioParam[commid].OpenFlag = OPEN_PORT;
//printf("设置Tcp端口%d 端口状态为OPEN_PORT\n", commid+1);
}
else
{
if(!IsBaoHuPtr(commid))
{
return;
}
if(NULL == SioParam[commid].WriteData)
{
return;
}
// 增加错误判断和断点续传
plen = SioParam[commid].WriteData->PLen;
slen = SioParam[commid].WriteData->MsgLen - plen;
if(slen <= 0)
{
DelNode(commid);
return;
}
len = send(SioParam[commid].CommSock,(const char*)&SioParam[commid].WriteData->MsgData[plen], slen, 0);
if(len > 0)
{
if(len < slen)
{
if(EINPROGRESS != errno)
{
//printf("端口%d 发送错误关闭Tcp通讯\n", commid+1);
CloseNetPort(commid);
}
else
{
SioParam[commid].WriteData->PLen += len;
}
}
else
{
DelNode(commid);
}
//ShmAddSendCount(commid, len);
}
else if(EINPROGRESS != errno)
{
//printf("端口%d 不能发送数据关闭Tcp通讯\n", commid+1);
CloseNetPort(commid);
}
}
}
void TcpAccept(int commid, int lisfds)
{
int sock, i, tmp;
#ifdef _WIN32
int result, addr_len;
#else
socklen_t result, addr_len;
#endif
struct sockaddr_in addr;
int keep_alive = 1; // 设定KeepAlive
int keep_idle = 5; // 开始首次KeepAlive探测前的TCP空闭时间
int keep_interval = 3; // 两次KeepAlive探测间的时间间隔
int keep_count = 3; // 判定断开前的KeepAlive探测次数
fd_set set;
u_long largp = 1L; //非阻塞模式
char tmp_buf[256];
addr_len = sizeof(struct sockaddr_in);
//printf("端口%d 检查是否有客户端过来连接\n", commid+1);
sock = accept(lisfds, (struct sockaddr *)&addr, &addr_len);
if(sock < 0)
{
return;
}
printf("TIP_(%04d): Port = %d, addr.sin_addr.s_addr(%08x), sock = %d\n", _getpid(), commid+1, addr.sin_addr.s_addr, sock);
// 多客户端向服务端连接时判断客户端来自的端口号 yizhonghu 20070704
for(i=MaxSerialPortNum; i<MaxPortNum; i++)
{
if((SioParam[i].NetCommIpAddr == addr.sin_addr.s_addr)
&& (SioParam[i].LiSock == lisfds))
{
printf("sockport = %d\n", i+1);
commid = i;
break;
}
}
if(i == MaxPortNum)
{
closesocket(sock);
return;
}
// 如果socket已经存在则关掉原来的连接建立新的连接 yizhonghu 20070705
if(SioParam[commid].CommSock < 0)
{
closesocket(SioParam[commid].CommSock);
}
SioParam[commid].CommSock = sock;
#ifdef OS_UNIX
result = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, result|O_NONBLOCK);
#else
result = ioctlsocket(sock, FIONBIO, (u_long *)&largp);
#endif
if (SOCKET_ERROR == result)
{
// result = WSAGetLastError();
// sprintf(tmp_buf, "ioctlsocket设置非阻塞模式错误, SocketError=%d, SocketId = %d", result, sock);
// DebugPrint(tmp_buf);
return;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
result = MAX_NET_BUF_SIZE;
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&result, sizeof(result));
result = MAX_NET_BUF_SIZE;
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&result, sizeof(result));
result = 4;
tmp_buf[0] = 1;
tmp = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, tmp_buf, result);
tmp = getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, tmp_buf, &result);
result = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&result, sizeof(result));
//set_keepalive(sock, keep_alive, keep_idle, keep_interval, keep_count);
// 这里应该等到确定端口可以写再设置为完全打开状态
//SioParam[commid].OpenFlag = OPEN_PORT;
}
int AddFdToSet(int commid, int *fd_max, fd_set *fdset_ro, fd_set *fdset_wr, fd_set *fdset_ex)
{
int setflag, fds, inum;
inum = 0;
setflag = 0;// (=0: 无操作; =1:没有后续操作; =2:当前无操作,但有后续操作;=3:有操作并有后续操作)
switch (SioParam[commid].NetType)
{
case NO_COMM:
break;
case UDP_COMM: // 检查UDP端口套接字是否建立
if (-1 < SioParam[commid].CommSock)
{
fds = SioParam[commid].CommSock;
setflag = 3;
break;
}
setflag = 2;
break;
case TCP_S_COMM: // 检查TCP服务器端口套接字是否建立(包括listen套接字)
if ((0 > SioParam[commid].CommSock) && (-1 < SioParam[commid].LiSock))
{
fds = SioParam[commid].LiSock;
setflag = 3;
break;
}
if (-1 < SioParam[commid].CommSock)
{
fds = SioParam[commid].CommSock;
setflag = 3;
break;
}
setflag = 2;
break;
case TCP_C_COMM: // 检查TCP客户端套接字是否建立
if (-1 < SioParam[commid].CommSock)
{
fds = SioParam[commid].CommSock;
setflag = 3;
break;
}
setflag = 2;
break;
}
if (0 == setflag)
return inum;
if ((1 == setflag) || (3 == setflag))
{
inum++;
FD_SET(fds, fdset_ro);
FD_SET(fds, fdset_wr);
FD_SET(fds, fdset_ex);
*fd_max = max(*fd_max, fds);
}
if (1 == setflag)
return inum;
// if(2 == setflag) 无需处理
return inum;
}
void PollAllPort(void)
{
struct timeval timeout;
int i, inum, nfds, commid, fds, lisfds, ret, ierr;
#ifdef _WIN32
int ierrlen;
#else
socklen_t ierrlen;
#endif
u_long ipaddr;
fd_set fdset_ro, fdset_wr, fdset_ex;
/*static int ok=0;*/
inum = 0;
nfds = 0;
FD_ZERO(&fdset_ro);
FD_ZERO(&fdset_wr);
FD_ZERO(&fdset_ex);
for(i=0; i<MaxPortNum; i++)
{
commid = i;
inum += AddFdToSet(commid, &nfds, &fdset_ro, &fdset_wr, &fdset_ex);
}
if(inum < 1)
return;
// 设置超时等待时间为0
memset((char*)&timeout, 0, sizeof(struct timeval));
if(select(nfds+1, &fdset_ro, &fdset_wr, &fdset_ex, &timeout) < 1)
{
return;
}
for(i=0; i< MaxPortNum; i++)
{
commid = i;
fds = SioParam[commid].CommSock;
ipaddr = SioParam[commid].NetCommIpAddr;
switch(SioParam[commid].NetType)
{
case NO_COMM:
break;
case UDP_COMM:
if(SioParam[commid].CommSock < 0)
break;
// 判断socket是否异常
if(FD_ISSET(fds, &fdset_ex))
{
CloseNetPort(commid);
break;
}
// socket可读
if(FD_ISSET(fds, &fdset_ro))
UdpRecv(commid, fds, ipaddr);// 将该socket中的数据读完
// socket可写
if(FD_ISSET(fds, &fdset_wr))
UdpSend(commid);
break;
case TCP_C_COMM:
if(SioParam[commid].CommSock < 0)
break;
// 判断socket是否异常
if(FD_ISSET(fds, &fdset_ex))
{
CloseNetPort(commid);
break;
}
// socket可读
if(FD_ISSET(fds, &fdset_ro))
{
if(TcpRecv(commid, fds, ipaddr) == FALSE) // 将该socket中的数据读完
break; // 端口可能已经关闭
}
// socket可写
if(FD_ISSET(fds, &fdset_wr))
{
ierrlen = sizeof(ierr);
ret = getsockopt (fds, SOL_SOCKET, SO_ERROR, (char *)&ierr, &ierrlen);
if (SOCKET_ERROR == ret)
{
CloseNetPort(commid);
break;
}
TcpSend(commid);
}
break;
case TCP_S_COMM:
lisfds = SioParam[commid].LiSock;
/*if(ok < 1000)
{
printf("端口%d lisock=%d fds = %d\n", commid+1, lisfds, fds);
ok++;
}*/
if(fds < 0)
{
if(lisfds < 0)
break;
if(FD_ISSET(lisfds, &fdset_ex))
{
//printf("端口%d 关闭服务器端口\n", commid+1);
CloseNetListenPort(commid);
}
else if(FD_ISSET(lisfds, &fdset_ro))
{
TcpAccept(commid, lisfds);
}
break;
}
// 判断socket是否异常
if(FD_ISSET(fds, &fdset_ex))
{
//printf("端口%d socket异常关闭Tcp通讯\n", commid+1);
CloseNetPort(commid);
break;
}
// socket可读
if(FD_ISSET(fds, &fdset_ro))
{
if(TcpRecv(commid, fds, ipaddr) == FALSE) // 将该socket中的数据读完
break; // 端口可能已经关闭
}
// socket可写
if(FD_ISSET(fds, &fdset_wr))
TcpSend(commid);
break;
}
}
// 服务器端口读写数据
}