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