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);   //等待被(信号)打断的情况, 重启select

        if (returnValue == 0) 
        {   //在waitTime时间段中一个事件也没到达,超时
            returnValue = -1;   //返回-1
            errno = 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 3031

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(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();
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章