套接字通信的Connect()功能
Connect() functionality of socket communication
关于socket通信的wallclock时间的问题。
我有一个功能,可以找到在中央服务器上注册的服务器。
我正在通过提取服务器的 URL 和端口号并尝试通过表现得像一个简单的 TCP 客户端来连接到它们来为此功能添加一层网络检查。
如果return值大于0,则说明网络正常;如果-1,则网络坏了。
printf("--Checking for network connectivity--\n");
for(size_t i = 0; i < serverOnNetworkSize; i++) {
UA_ServerOnNetwork *server = &serverOnNetwork[i];
A[i] = (char *)UA_malloc(server->discoveryUrl.length+1);
memcpy(A[i],server->discoveryUrl.data,server->discoveryUrl.length);
A[i][server->discoveryUrl.length] = 0;
int length = strlen(A[i]);
//discovery URLs are of the form : opc.tcp://hostname:port
//new addition to extract port
B[i] = A[i] + 10;
//printf("Hostname: %s\n", B[i]);
char *p = strrchr(B[i], ':');
int port = strtoul(p+1, NULL, 10);
//printf("%d\n",port);
B[i][length-5]='[=10=]';
//printf("Hostname: %s\n", B[i]);
//removing the port
A[i][length-5]='[=10=]';
//without initial tcp binding
C[i] = A[i] + 10;
//printf("Hostname: %s\n", C[i]);
// FIND IP OF THAT HOST
if(i!=0){
char ip_address[50];
find_ip_address(C[i],ip_address);
socketCommunication(ip_address,C[i],port);
}
}
printf("--Checks done!--\n");
全局函数:
int find_ip_address(char *hostname, char *ip_address)
{
struct hostent *host_name;
struct in_addr **ipaddress;
int count;
if((host_name = gethostbyname(hostname)) == NULL)
{
herror("\nIP Address Not Found\n");
return 1;
}
else
{
ipaddress = (struct in_addr **) host_name->h_addr_list;
for(count = 0; ipaddress[count] != NULL; count++)
{
strcpy(ip_address, inet_ntoa(*ipaddress[count]));
return 0;
}
}
return 1;
}
void socketCommunication(char *ip_address,char *hostname, int port){
int clientSocket,ret;
struct sockaddr_in serverAddr;
char buffer[1024];
clientSocket = socket(AF_INET,SOCK_STREAM,0);
if(clientSocket<0){
printf("Error in connection \n");
exit(1);
}
//printf("Client socket is created\n");
memset(&serverAddr,'[=11=]',sizeof(serverAddr));
serverAddr.sin_port = htons(port);
serverAddr.sin_family=AF_INET;
serverAddr.sin_addr.s_addr=inet_addr(ip_address);
ret = connect(clientSocket,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
if(ret<0){
printf("\nLOOKS LIKE NETWORK CONNECTION HAS FAILED. HAVE A LOOK AT THE NETWORK CONNECTIVITY at host : %s\n",hostname);
printf("\n----Updated Status Information----:\n");
printf("Discovery URL : opc.tcp://%s:%d\n",hostname,port);
printf("Status:CONNECTON TIMED OUT\n");
printf("\n");
}
为了对此进行测试,我关闭了其中一台注册服务器的网络。
当我测量时间时,它显示 18 秒、24、38 秒等不一致的值
这些值在我切换服务器网络和 运行 我的应用程序时出现。在同一应用程序的第二个 运行 上,该值有时会减少到 2 秒或 1 秒。
输出:
LOOKS LIKE NETWORK CONNECTION HAS FAILED. HAVE A LOOK AT THE NETWORK CONNECTIVITY at host : o755-gksr
----Updated Status Information----:
Discovery URL : opc.tcp://o755-gksr:4841
Status:CONNECTON TIMED OUT
--Checks done!--
Time measured: 18 seconds.
再试一次输出
--Checking for network connectivity--
LOOKS LIKE NETWORK CONNECTION HAS FAILED. HAVE A LOOK AT THE NETWORK CONNECTIVITY at host : o755-gksr
----Updated Status Information----:
Discovery URL : opc.tcp://o755-gksr:4841
Status:CONNECTON TIMED OUT
--Checks done!--
Time measured: 0 seconds.
我的问题是:为什么会显示不一致的值?如果无法连接,是否应该 return -1 并快速显示错误?
是否有任何后台进程在停止之前尝试建立有限次数的连接?
请告诉我。
此致,
洛山
connect()
行为及其超时在很大程度上取决于底层网络。目标机器宕机时 connect()
失败的原因还有很多。大多数情况下的错误是:
- ETIMEDOUT - 这意味着客户端发送了 SYN,但它根本没有收到任何响应。这是一个 TCP 超时,可能会很长(分钟)。
- EHOSTUNREACH - 这意味着本地 ARP 查询失败或客户端发送 SYN 和 ICMP 错误收到主机无法访问。几秒钟后检测到 ARP 查询失败。 ICMP 错误 Host Unreachable 通常由远程路由器在其 ARP 查询失败时返回。
那么,如果服务器与您的客户端位于同一网络中,您的情况会怎样:
- 客户端的 ARP 缓存中有服务器的 MAC 地址。
- 您“从其中一个注册服务器关闭网络。”。您可能从服务器或类似设备上断开电缆。
- 客户端调用connect。 SYN 直接从 ARP 缓存发送到 MAC 地址,最坏的情况是两分钟后使用 ETIMEDOUT 连接 returns。
- 客户端删除 ARP 缓存中的条目。
- 后续连接需要ARP解析。它要么在 3 个 ARP 请求(3 秒)后失败,要么在 ARP 缓存中的否定条目有效时立即失败。它可能只在几秒钟内有效。
如果服务器在远程网络中,则情况类似。在这种情况下,远程路由器的 ARP 缓存是有罪的。如果远程路由器无法将 IP 地址解析为 MAC 地址,则它几乎立即发送 ICMP 主机无法访问,但如果远程路由器在其 ARP 缓存中仍有目标 IP,则需要一些时间才能意识到缓存条目已过时,并且MAC 地址不可用。
关于socket通信的wallclock时间的问题。 我有一个功能,可以找到在中央服务器上注册的服务器。 我正在通过提取服务器的 URL 和端口号并尝试通过表现得像一个简单的 TCP 客户端来连接到它们来为此功能添加一层网络检查。 如果return值大于0,则说明网络正常;如果-1,则网络坏了。
printf("--Checking for network connectivity--\n");
for(size_t i = 0; i < serverOnNetworkSize; i++) {
UA_ServerOnNetwork *server = &serverOnNetwork[i];
A[i] = (char *)UA_malloc(server->discoveryUrl.length+1);
memcpy(A[i],server->discoveryUrl.data,server->discoveryUrl.length);
A[i][server->discoveryUrl.length] = 0;
int length = strlen(A[i]);
//discovery URLs are of the form : opc.tcp://hostname:port
//new addition to extract port
B[i] = A[i] + 10;
//printf("Hostname: %s\n", B[i]);
char *p = strrchr(B[i], ':');
int port = strtoul(p+1, NULL, 10);
//printf("%d\n",port);
B[i][length-5]='[=10=]';
//printf("Hostname: %s\n", B[i]);
//removing the port
A[i][length-5]='[=10=]';
//without initial tcp binding
C[i] = A[i] + 10;
//printf("Hostname: %s\n", C[i]);
// FIND IP OF THAT HOST
if(i!=0){
char ip_address[50];
find_ip_address(C[i],ip_address);
socketCommunication(ip_address,C[i],port);
}
}
printf("--Checks done!--\n");
全局函数:
int find_ip_address(char *hostname, char *ip_address)
{
struct hostent *host_name;
struct in_addr **ipaddress;
int count;
if((host_name = gethostbyname(hostname)) == NULL)
{
herror("\nIP Address Not Found\n");
return 1;
}
else
{
ipaddress = (struct in_addr **) host_name->h_addr_list;
for(count = 0; ipaddress[count] != NULL; count++)
{
strcpy(ip_address, inet_ntoa(*ipaddress[count]));
return 0;
}
}
return 1;
}
void socketCommunication(char *ip_address,char *hostname, int port){
int clientSocket,ret;
struct sockaddr_in serverAddr;
char buffer[1024];
clientSocket = socket(AF_INET,SOCK_STREAM,0);
if(clientSocket<0){
printf("Error in connection \n");
exit(1);
}
//printf("Client socket is created\n");
memset(&serverAddr,'[=11=]',sizeof(serverAddr));
serverAddr.sin_port = htons(port);
serverAddr.sin_family=AF_INET;
serverAddr.sin_addr.s_addr=inet_addr(ip_address);
ret = connect(clientSocket,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
if(ret<0){
printf("\nLOOKS LIKE NETWORK CONNECTION HAS FAILED. HAVE A LOOK AT THE NETWORK CONNECTIVITY at host : %s\n",hostname);
printf("\n----Updated Status Information----:\n");
printf("Discovery URL : opc.tcp://%s:%d\n",hostname,port);
printf("Status:CONNECTON TIMED OUT\n");
printf("\n");
}
为了对此进行测试,我关闭了其中一台注册服务器的网络。 当我测量时间时,它显示 18 秒、24、38 秒等不一致的值
这些值在我切换服务器网络和 运行 我的应用程序时出现。在同一应用程序的第二个 运行 上,该值有时会减少到 2 秒或 1 秒。
输出:
LOOKS LIKE NETWORK CONNECTION HAS FAILED. HAVE A LOOK AT THE NETWORK CONNECTIVITY at host : o755-gksr
----Updated Status Information----:
Discovery URL : opc.tcp://o755-gksr:4841
Status:CONNECTON TIMED OUT
--Checks done!--
Time measured: 18 seconds.
再试一次输出
--Checking for network connectivity--
LOOKS LIKE NETWORK CONNECTION HAS FAILED. HAVE A LOOK AT THE NETWORK CONNECTIVITY at host : o755-gksr
----Updated Status Information----:
Discovery URL : opc.tcp://o755-gksr:4841
Status:CONNECTON TIMED OUT
--Checks done!--
Time measured: 0 seconds.
我的问题是:为什么会显示不一致的值?如果无法连接,是否应该 return -1 并快速显示错误? 是否有任何后台进程在停止之前尝试建立有限次数的连接?
请告诉我。
此致, 洛山
connect()
行为及其超时在很大程度上取决于底层网络。目标机器宕机时 connect()
失败的原因还有很多。大多数情况下的错误是:
- ETIMEDOUT - 这意味着客户端发送了 SYN,但它根本没有收到任何响应。这是一个 TCP 超时,可能会很长(分钟)。
- EHOSTUNREACH - 这意味着本地 ARP 查询失败或客户端发送 SYN 和 ICMP 错误收到主机无法访问。几秒钟后检测到 ARP 查询失败。 ICMP 错误 Host Unreachable 通常由远程路由器在其 ARP 查询失败时返回。
那么,如果服务器与您的客户端位于同一网络中,您的情况会怎样:
- 客户端的 ARP 缓存中有服务器的 MAC 地址。
- 您“从其中一个注册服务器关闭网络。”。您可能从服务器或类似设备上断开电缆。
- 客户端调用connect。 SYN 直接从 ARP 缓存发送到 MAC 地址,最坏的情况是两分钟后使用 ETIMEDOUT 连接 returns。
- 客户端删除 ARP 缓存中的条目。
- 后续连接需要ARP解析。它要么在 3 个 ARP 请求(3 秒)后失败,要么在 ARP 缓存中的否定条目有效时立即失败。它可能只在几秒钟内有效。
如果服务器在远程网络中,则情况类似。在这种情况下,远程路由器的 ARP 缓存是有罪的。如果远程路由器无法将 IP 地址解析为 MAC 地址,则它几乎立即发送 ICMP 主机无法访问,但如果远程路由器在其 ARP 缓存中仍有目标 IP,则需要一些时间才能意识到缓存条目已过时,并且MAC 地址不可用。