原文链接:https://blog.csdn.net/chenhao0568/article/details/103420615
c语言linux TCP长连接 socket收发范例 断开自动重连
改进1:加入接收超时。可以做别的事,等有接收才响应
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <netinet/tcp.h>#include <string.h>#include <arpa/inet.h>#include <sys/socket.h>#include <errno.h>#include <sys/types.h>#include <netdb.h>#include <netinet/in.h>#include <time.h>#include <sys/timeb.h>#include <string.h>#include <stdio.h>#include <fcntl.h>#include <stdlib.h>#include <unistd.h>#include <sys/stat.h>#include <locale.h>// #include "extra/curl/curl.h"//#define IP "192.168.1.127"
#define IP "10.0.0.30"
#define PORT 3031
long time_last_connected = 0;// //参数解释
// //fd: 网络连接描述符
// //start: 首次心跳侦测包发送之间的空闲时间
// //interval: 两次心跳侦测包之间的间隔时间
// //count: 探测次数,即将几次探测失败判定为TCP断开
// int set_tcp_keepAlive(int fd, int start, int interval, int count)
// {
// int keepAlive = 1;
// //入口参数检查 ,编程的好习惯。
// if (fd < 0 || start < 0 || interval < 0 || count < 0)
// return -1;
// //启用心跳机制,如果您想关闭,keepAlive置零即可
// if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*) &keepAlive, sizeof(keepAlive)) == -1)
// {
// perror("setsockopt");
// return -1;
// }
// //启用心跳机制开始到首次心跳侦测包发送之间的空闲时间
// if (setsockopt(fd, IPPROTO_TCP , TCP_KEEPIDLE, (void *) &start, sizeof(start)) == -1)
// {
// perror("setsockopt");
// return -1;
// }
// //两次心跳侦测包之间的间隔时间
// if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, (void *) &interval, sizeof(interval)) == -1)
// {
// perror("setsockopt");
// return -1;
// }
// //探测次数,即将几次探测失败判定为TCP断开
// if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, (void *) &count, sizeof(count)) == -1)
// {
// perror("setsockopt");
// return -1;
// }
// return 0;
// }
/***read_timeout - 读超时检测函数, 不包含读操作*@fd: 文件描述符*@waitSec: 等待超时秒数, 0表示不检测超时*成功(未超时)返回0, 失败返回-1, 超时返回-1 并且 errno = ETIMEDOUT**/
int read_timeout(int fd, long waitSec)
{int returnValue = 0;if (waitSec > 0) {fd_set readSet;FD_ZERO(&readSet);FD_SET(fd, &readSet); //添加struct timeval waitTime;waitTime.tv_sec = waitSec;waitTime.tv_usec = 0; //将微秒设置为0(不进行设置),如果设置了,时间会更加精确do{returnValue = select(fd + 1, &readSet, NULL, NULL, &waitTime);}while (returnValue < 0 && errno == EINTR); //等待被(信号)打断的情况, 重启selectif (returnValue == 0) { //在waitTime时间段中一个事件也没到达,超时returnValue = -1; //返回-1errno = ETIMEDOUT;}else if (returnValue == 1) { //在waitTime时间段中有事件产生returnValue = 0; //返回0,表示成功}// 如果(returnValue == -1) 并且 (errno != EINTR), 则直接返回-1(returnValue)}printf("TCP read_timeout:%d\n",returnValue);return returnValue;
}
// /* activate_nonblock - 设置IO为非阻塞模式
// * fd: 文件描述符
// */
// void activate_nonblock(int fd)
// {
// int ret;
// int flags = fcntl(fd, F_GETFL);
// if (flags == -1)
// {
// perror("fcntl error");
// }
// flags |= O_NONBLOCK;
// ret = fcntl(fd, F_SETFL, flags);
// if (ret == -1)
// {
// perror("fcntl error");
// }
// }
// /* deactivate_nonblock - 设置IO为阻塞模式
// * fd: 文件描述符
// */
// void deactivate_nonblock(int fd)
// {
// int ret;
// int flags = fcntl(fd, F_GETFL);
// if (flags == -1)
// {
// perror("fcntl error");
// }
// flags &= ~O_NONBLOCK;
// ret = fcntl(fd, F_SETFL, flags);
// if (ret == -1)
// {
// perror("fcntl error");
// }
// }/* connect_timeout - 带超时的connect* fd: 套接字* addr: 输出参数,返回对方地址* wait_seconds: 等待超时秒数,如果为0表示正常模式* 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT*/
// int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
// {
// int ret;
// socklen_t addrlen = sizeof(struct sockaddr_in);// if (wait_seconds > 0)
// {
// activate_nonblock(fd); //设置为非阻塞模式
// }
// printf("\n连接服务器开始\n");
// ret = connect(fd, (struct sockaddr *) addr, addrlen);
// printf("\n连接服务器开始[%d,%d]\n", ret,errno);
// if (ret < 0 && errno == EINPROGRESS)
// {
// printf("connect EINPROGRESS\n"); //异步连接
// fd_set connect_fdset;
// struct timeval timeout;
// FD_ZERO(&connect_fdset);
// FD_SET(fd, &connect_fdset);// timeout.tv_sec = wait_seconds;
// timeout.tv_usec = 0;// do
// {
// /* 一旦连接建立,套接字就可写 */
// ret = select(fd + 1, NULL, &connect_fdset, NULL, &timeout);
// }
// while (ret < 0 && errno == EINTR);// if (ret == 0)
// {
// errno = ETIMEDOUT;
// return -1;
// }
// else if (ret < 0)
// return -1;// else if (ret == 1)
// {
// /* ret返回为1,可能有两种情况,一种是连接建立成功,一种是套接字产生错误
// * 此时错误信息不会保存至errno变量中(select没出错),因此,需要调用
// * getsockopt来获取 */
// int err;
// socklen_t socklen = sizeof(err);
// int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &socklen);
// if (sockoptret == -1)
// {
// return -1;
// }
// if (err == 0)
// {
// ret = 0;
// }
// else
// {
// errno = err;
// ret = -1;
// }
// }
// }
// if (wait_seconds > 0)
// {
// deactivate_nonblock(fd);
// }
// return ret;
// }
int tcp()
{printf("\n\n**********TCP开始连接%s:%d\n", IP, PORT);int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){printf("socket创建失败:%d\n", sockfd);close(sockfd);sleep(1);return -1;}// printf("socket创建成功:%d\n", sockfd);struct sockaddr_in ser;memset(&ser, 0, sizeof(ser));ser.sin_family = AF_INET;ser.sin_port = htons(PORT);ser.sin_addr.s_addr = inet_addr(IP);int res = connect(sockfd, (struct sockaddr *)&ser, sizeof(ser));if (res < 0){printf("socket连接失败:%d\n", res);close(sockfd);sleep(1);return -1;}printf("socket连接成功:%d\n", res);while (1){//发送//printf("please input:");fflush(stdin);//清理标准输入流,把多余的未被保存的数据丢掉。char buff[128] = "1234";//fgets(buff, 128, stdin);//buff[strlen(buff) - 1] = 0;if (strcmp(buff, "end") == 0) //end正常退出{close(sockfd);printf("end正常退出socket\n");return 0;}int sendret = send(sockfd, buff, strlen(buff), 0);if (sendret < 0){printf("socket发送失败:%d (0服务端断开,-1网络故障)\n", sendret);close(sockfd);return -1;}printf("socket发送成功:%d,内容:%s\n", sendret, buff);//接收char recvbuff[1024] = {0};printf("socket接收等待中\n");fflush(stdout);//清空输出缓冲区,并把缓冲区内容输出。int ret = read_timeout(sockfd, 10);if(ret==0){int recvret = recv(sockfd, recvbuff, 1023, 0);if (recvret <= 0){printf("socket接收失败:%d (0服务端断开,-1网络故障)\n", recvret);close(sockfd);return -1;}printf("socket接收成功:%d,内容:%s\n", recvret, recvbuff);}}
}
int main()
{while (1){tcp();}
}
阻塞
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define IP "192.168.1.127"
#define PORT 3031int tcp()
{printf("\n\n**********TCP开始连接%s:%d\n", IP, PORT);int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){printf("socket创建失败:%d\n", sockfd);close(sockfd);sleep(1);return -1;}// printf("socket创建成功:%d\n", sockfd);struct sockaddr_in ser;memset(&ser, 0, sizeof(ser));ser.sin_family = AF_INET;ser.sin_port = htons(PORT);ser.sin_addr.s_addr = inet_addr(IP);int res = connect(sockfd, (struct sockaddr *)&ser, sizeof(ser));if (res < 0){printf("socket连接失败:%d\n", res);close(sockfd);sleep(1);return -1;}printf("socket连接成功:%d\n", res);while (1){//发送//printf("please input:");fflush(stdout);char buff[128] = "1234";//fgets(buff, 128, stdin);//buff[strlen(buff) - 1] = 0;if (strcmp(buff, "end") == 0) //end正常退出{close(sockfd);printf("end正常退出socket\n");return 0;}int sendret = send(sockfd, buff, strlen(buff), 0);if (sendret < 0){printf("socket发送失败:%d (0服务端断开,-1网络故障)\n", sendret);close(sockfd);return -1;}printf("socket发送成功:%d,内容:%s\n", sendret, buff);//接收char recvbuff[128] = {0};printf("socket接收等待中\n");int recvret = recv(sockfd, recvbuff, 127, 0);if (recvret <= 0){printf("socket接收失败:%d (0服务端断开,-1网络故障)\n", recvret);close(sockfd);return -1;}printf("socket接收成功:%d,内容:%s\n", recvret, recvbuff);}
}
int main()
{while (1){tcp();}
}