c - 套接字通信的 Connect() 功能
问题描述
关于socket通信挂钟时间的问题。我有一个功能,可以找到在中央服务器上注册的服务器。我通过提取服务器的 URL 和端口号并尝试通过表现得像一个简单的 TCP 客户端来连接到它们,从而在此功能上添加一层网络检查。如果返回值大于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]='\0';
//printf("Hostname: %s\n", B[i]);
//removing the port
A[i][length-5]='\0';
//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,'\0',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.
我的问题是:为什么它显示不一致的值?如果无法连接,是否不应该返回 -1 并快速显示错误?是否有任何后台进程在停止之前尝试建立连接有限次?
请告诉我。
问候, 罗山
解决方案
connect()
行为及其超时高度依赖于底层网络。connect()
目标机器停机时失败的原因还有很多。大多数情况下的错误是:
- ETIMEDOUT - 这意味着客户端发送了 SYN,但它根本没有收到任何响应。这是一个 TCP 超时,可能会很长(几分钟)。
- EHOSTUNREACH - 这意味着本地 ARP 查询失败或客户端发送 SYN 和 ICMP 错误 Host Unreachable 已收到。在几秒钟内检测到 ARP 查询失败。ICMP 错误 Host Unreachable 通常由远程路由器在其 ARP 查询失败时返回。
那么,如果服务器与您的客户端位于同一网络中,您的情况会发生什么:
- 客户端的 ARP 缓存中有服务器的 MAC 地址。
- 您“从其中一台已注册的服务器上关闭网络。 ”。您可能从服务器或类似的东西上断开电缆。
- 客户端调用连接。SYN 直接从 ARP 缓存发送到 MAC 地址,在最坏的情况下,连接会在两分钟后返回 ETIMEDOUT。
- 客户端删除 ARP 缓存中的条目。
- 后续连接需要 ARP 解析。要么在 3 次 ARP 请求(3 秒)后失败,要么在 ARP 缓存中的否定条目有效时立即失败。它可能仅在几秒钟内有效。
如果服务器在远程网络中,则情况类似。在这种情况下,远程路由器的 ARP 缓存是有罪的。如果远程路由器无法将 IP 地址解析为 MAC 地址,则它几乎立即发送 ICMP Host Unreachable 但如果远程路由器在其 ARP 缓存中仍有目标 IP,则它需要一些时间才能意识到缓存条目已过时且 MAC 地址不是可用的。
推荐阅读
- javascript - JavaSript:为什么我的代码要修改原始数据对象上的对象数组?
- laravel - 如何在 plesk windows 服务器上运行 laravel 6 的计划任务
- php - 如何为简单视图制作准备好的声明?
- rust - 是否可以向下转换 Arc
到弧 >? - python - osx 上的比特币核心和 bitcoinlib 套接字错误
- python - discord.ext.commands.errors.CommandInvokeError:命令引发异常:NoEntryPointError:扩展“cogs.help”没有“设置”功能
- oracle - 如何显示另一个表的计数?
- c - 有没有办法让这个 MergeSort 算法更有效?
- mysql - 有没有办法在MySQL中计算后列出不同值的内容?
- php - 构造函数控制器中的重定向不起作用codeigniter4