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

 

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