1.代码展示
int TcpClient::connect(int timeout)
{
if(isConnected){
return 0;
}
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(clientSocket < 0){
isConnected = false;
return -1;
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(m_serverIP.c_str());
serv_addr.sin_port = htons(m_serverPort);
int flags = fcntl(clientSocket, F_GETFL, 0);
if(flags < 0){
perror("Get flags error.");
::close(clientSocket);
isConnected = false;
return -1;
}
flags |= O_NONBLOCK;
if(fcntl(clientSocket, F_SETFL, flags) < 0){
perror("Set flags error.");
::close(clientSocket);
isConnected = false;
return -1;
}
fd_set writeFd;
struct timeval stTimeout;
int rc = ::connect(clientSocket, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if(rc != 0){
if(errno == EINPROGRESS){
printf("Doing Connection.\n");
//establish connection.
FD_ZERO(&fdw);
FD_SET(clientSocket, &fdw);
if(timeout != -1){
stTimeout.tv_sec = timeout / 1000;
stTimeout.tv_usec = (timeout % 1000) * 1000;
}
rc = select(clientSocket + 1, NULL, &fdw, NULL, &stTimeout);
if(rc < 0){
fprintf(stderr, "Connect Error:%s\n", strerror(errno));
close(clientSocket);
isConnected = false;
return -1;
}
else if(rc == 0){//connect timeout.
fprintf(stderr, "Connect Timeout.\n");
close(clientSocket);
isConnected = false;
return -1;
}
else{
int err = 0;
uint32_t errlen = sizeof(err);
if(getsockopt(clientSocket, SOL_SOCKET, SO_ERROR, &err, &errlen) != 0){
fprintf(stderr, "getsockopt(SO_ERROR): %s", strerror(errno));
close(clientSocket);
isConnected = false;
return -1;
}
if(err){
errno = err;
fprintf(stderr, "Connect Error:%s\n", strerror(errno));
close(clientSocket);
isConnected = false;
return -1;
}else{
isConnected = true;
return 0;
}
}
}
else{
fprintf(stderr, "Connect Failed, error: %s.\n", strerror(errno));
close(clientSocket);
isConnected = false;
return -1;
}
}
isConnected = true;
if(pthread_create(&workThreadID, NULL, worker, NULL) != 0){
printf("Create Worker Thread Failed.\n");
}
printf("connect success\n");
return 0;
}
2.流程如下:
创建socket
创建stuct sockaddr_in 并设置port、ip
fcntl设置为非阻塞
连接服务器connect
-->连接失败
清空、添加fd_set
select 检查文件描述符

-->超时
-->关闭套接字
-->出错
-->关闭套接字
-->有事件发生
-->获取套接字属性
-->连接成功
recv
设置 需要读取的字节数,超时时间
while (readSize < wantSize)
-->清空、添加fd_set
-->select 检查文件描述符
-->超时
-->返回
-->正常 && clientSocket在集合中
接收clientSocket消息
-->失败
-->errno == EAGAIN
返回readSize
-->else
断开连接
-->超时
断开连接
-->接收消息并更新readSize
返回readSize
3.connect()的连接时间
1、如果套接字为阻塞模式下,一般是3分钟,就是如果3分钟内没有连接上就会退出;
2、如果套接字非阻塞模式下,则会立即返回;

成功:返回 0。
失败:返回 -1,并设置 errno。
浙公网安备 33010602011771号