/***************************************************************************** * 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 #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 -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= 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 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