123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- #include "communication_tcp.h"
- #include "string.h"
- Communication_tcp::Communication_tcp()
- {
- }
- Communication_tcp::~Communication_tcp()
- {
- }
- bool Communication_tcp::communication_tcp_init() //创建套接字
- {
- //创建socket (TCP/IP协议 TCP)
- m_socket = socket(AF_INET, SOCK_STREAM, 0); //直接创建socket返回给Communication_tcp的成员
- if (m_socket == -1)
- {
- printf(" create tcp socket failed ");
- return false;
- }
- else
- {
- //printf(" create tcp socket successed ");
- return true;
- }
- }
- bool Communication_tcp::communication_tcp_bind(const char *ip,unsigned short port) //绑定并监听端口号(服务端用)
- {
- sockaddr_in saddr; //数据结构
- saddr.sin_family = AF_INET; //协议
- saddr.sin_port = htons(port); //端口,主机字节序(小端方式)转换成网络字节序(大端方式)
- saddr.sin_addr.s_addr = inet_addr(ip); //绑定IP
- if (bind(m_socket, (sockaddr*)&saddr, sizeof(saddr)) != 0)
- {
- printf(" tcp bind ip:%s port:%d failed\n",ip,port);
- return false;
- }
- printf(" tcp bind ip:%s port:%d success\n",ip,port);
- return true;
- }
- bool Communication_tcp::communication_tcp_listen(unsigned short num) //最大连接数
- {
- int re = listen(m_socket, num); //套接字,最大请求队列的长度 进入阻塞状态
- if(!re)
- {
- printf(" tcp socket listen start ");
- return true;
- }
- else
- {
- printf(" tcp socket listen failed ");
- return false;
- }
- }
- bool Communication_tcp::set_block(bool isblock) //设置阻塞模式 (希望只有在connect的时候是非阻塞的,而接收数据时候是阻塞的)
- {
- if (m_socket <= 0)
- {
- printf(" set tcp socket block failed\n ");
- return false;
- }
- int flags = fcntl(m_socket, F_GETFL, 0); //获取socket的属性
- if (flags < 0)
- return false; //获取属性出错
- if (isblock)
- {
- flags = flags&~O_NONBLOCK; //把非阻塞这位设为0
- }
- else
- {
- flags = flags | O_NONBLOCK; //把非阻塞这位设为1
- }
- if (fcntl(m_socket, F_SETFL, flags))
- return false; //把标准位设回去
- // if (!isblock)
- // printf("set tcp socket not block success\n");
- // if (isblock)
- // printf("set tcp socket block success\n");
- return true;
- }
- bool Communication_tcp::communication_tcp_connect(const char *ip, unsigned short port , int sec)
- {
- if (m_socket <= 0)
- return false;
- sockaddr_in saddr; //设置连接对象的结构体
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(port);
- saddr.sin_addr.s_addr = inet_addr(ip); //字符串转整型
- set_block(false); //将socket改成非阻塞模式,此时它会立即返回 所以通过fd_set
- fd_set rfds, wfds; //文件句柄数组,在这个数组中,存放当前每个文件句柄的状态
- if (connect(m_socket, (sockaddr*)&saddr, sizeof(saddr)) != 0) //此时connect马上返回,状态为未成功连接
- {
- FD_ZERO(&rfds); //首先把文件句柄的数组置空
- FD_ZERO(&wfds);
- FD_SET(m_socket, &rfds); //把sock的网络句柄加入到该句柄数组中
- FD_SET(m_socket, &wfds);
- timeval tm; //超时参数的结构体
- tm.tv_sec = sec;
- tm.tv_usec = 0;
- int selres = select(m_socket + 1, &rfds, &wfds, NULL, &tm); //(阻塞函数)(监听的文件句柄的最大值加1,可读序列文件列表,可写的序列文件列表,错误处理,超时)使用select监听文件序列set是否有可读可写,这里监听set数组(里面只有sock),只要其中的句柄有一个变得可写(在这里是sock连接成功了以后就会变得可写,就返回),就返回
- switch (selres)
- {
- case -1:
- printf("select error\n");
- return false;
- case 0:
- printf("select time out\n");
- return false;
- default:
- if (FD_ISSET(m_socket, &rfds) || FD_ISSET(m_socket, &wfds))
- {
- connect(m_socket, (sockaddr*)&saddr, sizeof(saddr)); //再次连接一次进行确认
- int err = errno;
- if (err == EISCONN||err == EINPROGRESS) //已经连接到该套接字 或 套接字为非阻塞套接字,且连接请求没有立即完成
- {
- //printf("connect %s : %d finished(success).\n",ip,port);
- set_block(true); //成功之后重新把sock改成阻塞模式,以便后面发送/接收数据
- return true;
- }
- else
- {
- printf("connect %s : %d finished(failed). errno = %d\n",ip,port,errno);
- // printf("FD_ISSET(sock_fd, &rfds): %d\n FD_ISSET(sock_fd, &wfds): %d\n", FD_ISSET(sock_fd, &rfds) , FD_ISSET(sock_fd, &wfds));
- return false;
- }
- }
- else
- {
- printf("connect %s : %d finished(failed).",ip,port);
- return false;
- }
- }
- }
- else //连接正常
- {
- set_block(true); //成功之后重新把sock改成阻塞模式,以便后面发送/接收数据
- printf("connect %s : %d finished(success).\n",ip,port);
- return true;
- }
- }
- bool Communication_tcp::communication_tcp_connect(int sec)
- {
- if (m_socket <= 0) return false;
- sockaddr_in saddr; //设置连接对象的结构体
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(m_server_port);
- saddr.sin_addr.s_addr = inet_addr(m_server_ip); //字符串转整型
- set_block(false); //将socket改成非阻塞模式,此时它会立即返回 所以通过fd_set
- fd_set rfds, wfds; //文件句柄数组,在这个数组中,存放当前每个文件句柄的状态
- if (connect(m_socket, (sockaddr*)&saddr, sizeof(saddr)) != 0) //此时connect马上返回,状态为未成功连接
- {
- FD_ZERO(&rfds); //首先把文件句柄的数组置空
- FD_ZERO(&wfds);
- FD_SET(m_socket, &rfds); //把sock的网络句柄加入到该句柄数组中
- FD_SET(m_socket, &wfds);
- timeval tm; //超时参数的结构体
- tm.tv_sec = sec;
- tm.tv_usec = 0;
- int selres = select(m_socket + 1, &rfds, &wfds, NULL, &tm); //(阻塞函数)(监听的文件句柄的最大值加1,可读序列文件列表,可写的序列文件列表,错误处理,超时)使用select监听文件序列set是否有可读可写,这里监听set数组(里面只有sock),只要其中的句柄有一个变得可写(在这里是sock连接成功了以后就会变得可写,就返回),就返回
- switch (selres)
- {
- case -1:
- printf("select error\n");
- return false;
- case 0:
- printf("select time out\n");
- return false;
- default:
- if (FD_ISSET(m_socket, &rfds) || FD_ISSET(m_socket, &wfds))
- {
- connect(m_socket, (sockaddr*)&saddr, sizeof(saddr)); //再次连接一次进行确认
- int err = errno;
- if (err == EISCONN||err == EINPROGRESS) //已经连接到该套接字 或 套接字为非阻塞套接字,且连接请求没有立即完成
- {
- //printf("connect %s : %d finished(success).\n",m_server_ip,m_server_port);
- set_block(true); //成功之后重新把sock改成阻塞模式,以便后面发送/接收数据
- return true;
- }
- else
- {
- printf("connect %s : %d finished(failed). errno = %d\n",m_server_ip,m_server_port,errno);
- // printf("FD_ISSET(sock_fd, &rfds): %d\n FD_ISSET(sock_fd, &wfds): %d\n", FD_ISSET(sock_fd, &rfds) , FD_ISSET(sock_fd, &wfds));
- return false;
- }
- }
- else
- {
- printf("connect %s : %d finished(failed).",m_server_ip,m_server_port);
- return false;
- }
- }
- }
- else //连接正常
- {
- printf("connect %s : %d finished(success).\n",m_server_ip,m_server_port);
- set_block(true); //成功之后重新把sock改成阻塞模式,以便后面发送/接收数据
- return true;
- }
- }
- Communication_tcp Communication_tcp::Accept() //返回Communication_tcp对象,接收连接
- {
- Communication_tcp tcp; //先定义一个Communication_tcp对象,一会返回它
- sockaddr_in caddr;
- socklen_t len = sizeof(caddr);
- tcp.m_socket = accept(m_socket, (sockaddr*)&caddr, &len); //(阻塞)接收连接 ,会创建一个新的socket,一般扔到一个单独线程与这个客户端进行单独通信,之前的sock只用来建立连接
- if (tcp.m_socket <= 0)
- return tcp; //出错
- printf("accept client socket %d\n", tcp.m_socket);
- char *ip = inet_ntoa(caddr.sin_addr); //解析出IP地址 ,转换到字符串
- strcpy(tcp.m_client_ip, ip);
- tcp.m_client_port = ntohs(caddr.sin_port); //解析出端口,转换成主机字节序
- printf("client ip is %s,port is %d\n", tcp.m_client_ip, tcp.m_client_port); //打印ip和端口
- return tcp;
- }
- void Communication_tcp::communication_tcp_uninit() //关闭连接
- {
- if (m_socket <= 0)
- {
- printf("socket %d error \n", m_socket); //打印ip和端口
- return; //socket出错
- }
- close(m_socket);
- }
- int Communication_tcp::communication_tcp_recv(char *buf, int size) //接收数据
- {
- return recv(m_socket, buf, size, 0);
- }
- int Communication_tcp::communication_tcp_send(const char *buf, int size) //发送数据
- {
- int sendedSize = 0; //已发送成功的长度
- while (sendedSize != size) //若没发送完成,则从断点开始继续发送 直到完成
- {
- try
- {
- int len = send(m_socket, buf + sendedSize, size - sendedSize, 0);
- if (len <= 0)
- break;
- sendedSize += len;
- }
- catch (char *str)
- {
- std::cout << " 断线---" << str<< std::endl;
- break;
- }
- }
- return sendedSize;
- }
- int Communication_tcp::set_recv_timeout(int sec) //设置tcp接收超时
- {
- struct timeval tcp_rev_time;
- tcp_rev_time.tv_sec = sec;
- tcp_rev_time.tv_usec = 0;
- if (setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tcp_rev_time, sizeof(tcp_rev_time))<0)
- {
- printf("set tcp receive failed.\n");
- return -1;
- }
- printf("set tcp recv timeout success. %d seconds.\n", sec);
- return 0;
- }
- int Communication_tcp::set_send_timeout(int sec) //设置tcp发送超时
- {
- struct timeval tcp_send_time;
- tcp_send_time.tv_sec = sec;
- tcp_send_time.tv_usec = 0;
- if (setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tcp_send_time, sizeof(tcp_send_time))<0)
- {
- printf("set tcp send failed.\n");
- return -1;
- }
- printf("set tcp recv timeout success. %d seconds.\n", sec);
- return 0;
- }
- bool Communication_tcp::is_connected()
- {
- struct tcp_info info;
- int len=sizeof(info);
- getsockopt(m_socket, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
- if((info.tcpi_state==TCP_ESTABLISHED))
- {
- return true;
- }
- return false;
- }
|