|
@@ -0,0 +1,330 @@
|
|
|
+#include "communication_socket.h"
|
|
|
+#include "string.h"
|
|
|
+Communication_socket::Communication_socket()
|
|
|
+{
|
|
|
+}
|
|
|
+Communication_socket::~Communication_socket()
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+bool Communication_socket::communication_socket_init() //创建套接字
|
|
|
+{
|
|
|
+
|
|
|
+ //创建socket (TCP/IP协议 TCP)
|
|
|
+ m_socket = socket(AF_INET, SOCK_STREAM, 0); //直接创建socket返回给Communication_socket的成员
|
|
|
+ if (m_socket == -1)
|
|
|
+ {
|
|
|
+ printf(" create tcp socket failed ");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //printf(" create tcp socket successed ");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+bool Communication_socket::communication_socket_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_socket::communication_socket_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_socket::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_socket::communication_socket_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_socket::communication_socket_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_socket Communication_socket::Accept() //返回Communication_socket对象,接收连接
|
|
|
+{
|
|
|
+ Communication_socket tcp; //先定义一个Communication_socket对象,一会返回它
|
|
|
+
|
|
|
+ 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_socket::communication_socket_uninit() //关闭连接
|
|
|
+{
|
|
|
+ if (m_socket <= 0)
|
|
|
+ {
|
|
|
+ printf("socket %d error \n", m_socket); //打印ip和端口
|
|
|
+ return; //socket出错
|
|
|
+ }
|
|
|
+ close(m_socket);
|
|
|
+}
|
|
|
+
|
|
|
+int Communication_socket::communication_socket_recv(char *buf, int size) //接收数据
|
|
|
+{
|
|
|
+ return recv(m_socket, buf, size, 0);
|
|
|
+}
|
|
|
+
|
|
|
+int Communication_socket::communication_socket_send(const char *buf, int size) //发送数据
|
|
|
+{
|
|
|
+ int sendedSize = 0; //已发送成功的长度
|
|
|
+
|
|
|
+ while (sendedSize != size) //若没发送完成,则从断点开始继续发送 直到完成
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if(is_connected())
|
|
|
+ {
|
|
|
+ int len = send(m_socket, buf + sendedSize, size - sendedSize, 0);
|
|
|
+ if (len <= 0)
|
|
|
+ break;
|
|
|
+ sendedSize += len;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ catch(std::exception e)
|
|
|
+ {
|
|
|
+ std::cout << " send error 断线---" << std::endl;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ return sendedSize;
|
|
|
+}
|
|
|
+
|
|
|
+int Communication_socket::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_socket::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_socket::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;
|
|
|
+}
|
|
|
+
|