gpt4 book ai didi

c - 使用C使用TCP连接到端口

转载 作者:可可西里 更新时间:2023-11-01 02:32:26 26 4
gpt4 key购买 nike

我对套接字和任何类型的网络编程都是99%的新手,所以请多多包涵。

我的目标是连接到本地计算机(192.168.0.1)上的端口(在这种情况下为2111)。从那里,我正计划发送和接收基本信息,但是那是另一天。

我目前已经尝试过:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char **argv)
{
int sd;
int port;
int start;
int end;
int rval;
struct hostent *hostaddr;
struct sockaddr_in servaddr;

start = 2111;
end = 2112;
for(port = start; port <= end; port++)
{
sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sd == -1)
{
perror("Socket()\n");
return (errno);
}

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);

hostaddr = gethostbyname("192.168.0.1");

memcpy(&servaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);

rval = connect(sd, (struct sockaddr *)&servaddr, sizeof(servaddr));
if(rval == -1)
{
printf("Port %d is closed\n", port);
close(sd);
}
else printf("Port %d is open\n", port);

close(sd);
}

return 0;
}

但是,我的 connect()调用挂起约90秒,然后返回-1。

该设备直接连接到Mac Mini的以太网端口,并且制造商已确认该端口为2111或2112。

我究竟做错了什么?另外,它可以采用ELI5(就像我5岁时那样解释)格式吗?我举几个例子要好得多。

最佳答案

当您调用connect()连接到主机时,您的计算机将发送SYN数据包以开始TCP连接的three-way handshake。从这里开始,有3种可能的情况:

  • 如果对等方正在该端口上监听,它将以SYN + ACK数据包作为响应,您的计算机以最终的ACK作为响应,并且连接已建立-connect()成功返回。
  • 如果对等方不在该端口上监听,它将以类型和代码表示该端口已关闭的ICMP数据包作为响应,这会导致connect()调用几乎立即失败,并显示错误ECONNREFUSED(连接被拒绝)。在正常情况下,这需要1个网络往返时间(RTT),通常为数十或数百毫秒。
  • 如果您的计算机从未收到适当的SYN + ACK TCP数据包或连接被拒绝的ICMP数据包,则它假定其原始SYN数据包已被某个地方的网络丢弃,并将尝试多次重新发送SYN数据包,直到获得其中一个数据包为止。 back或遇到与操作系统有关的超时,此时connect()调用失败,并显示ETIMEDOUT。这通常是1-2分钟,具体取决于操作系统及其TCP设置。

  • 您显然正在处理第3个案例。这可能是由几个不同的问题引起的:
  • 您的原始SYN数据包已在网络中丢失,可能是由于链路故障,路由器重载或防火墙
  • 对等方的SYN + ACK或ICMP响应数据包在网络中丢失,可能是由于链路故障,路由器重载或防火墙
  • 目的地地址可能无法路由/无法访问
  • 对等方可能根本无法正确响应SYN + ACK或ICMP数据包

  • 如果您是直接通过以太网连接到设备,则排除#1和#2。 #4是可能的,但我认为#3是最可能的解释。

    简要介绍数据包路由

    您的计算机具有多个网络接口(interface)-以太网(有时为多个以太网接口(interface)),Wi-Fi,环回设备,VPN隧道等。每当您创建套接字时,都必须将其绑定(bind)到一个或多个特定的网络接口(interface),以便进行连接。操作系统知道实际通过哪个NIC发送数据包。对于服务器的监听套接字,通常绑定(bind)到所有网络接口(interface)(以监听所有接口(interface)),但是也可以绑定(bind)到特定的网络接口(interface)以仅监听该接口(interface)。

    对于客户端套接字,将它们连接到其他对等端时,通常不会将它们绑定(bind)到特定接口(interface)。默认情况下,您的计算机使用其内部路由表以及目标IP地址来确定要使用的网络接口(interface)。例如,如果您有一台具有两个NIC的网关计算机,其中一个通过IP 54.xyz连接到公共(public)互联网,而另一个通过IP 192.168.1.1连接到内部专用网络,则该计算机将路由表极有可能说“对于发往192.168.0.0/16的数据包,请使用NIC 2,对于所有其他数据包,请使用NIC 1”。如果要绕过路由表,可以通过在调用 bind()之前在套接字上调用 connect()来将套接字绑定(bind)到所需的网络接口(interface)。

    全部放在一起

    那么,这对您意味着什么呢?

    首先,确保192.168.0.1实际上是您应该连接的正确目标地址。该地址如何确定?您的计算机是否充当DHCP服务器,以将该地址分配给另一台主机?该主机是否使用静态IP配置?

    接下来,确保您的路由表正确。如果另一台计算机为其自身分配了静态IP,则很可能是您的Mac不知道如何路由到该目的地,并且可能正在尝试通过错误的接口(interface)进行路由。您可以使用 route(8) utility在Mac OS X上手动调整路由,但是每次重新启动时都会重置这些路由。 this blog post显示了一个示例,该示例使用启动项在启动时自动添加新路由。您将要使用与连接到目标主机的以太网接口(interface)关联的IP地址。

    另外,除了使用路由表之外,您还可以在套接字上调用 bind(),然后再将 connect()绑定(bind)到要使用的接口(interface)的本地地址,但这不适用于其他程序,除非它们也提供了该功能。例如, curl(1)实用程序使您可以传递 --interface <name>命令行标志来指示它绑定(bind)到特定接口(interface)。

    关于c - 使用C使用TCP连接到端口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24766627/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com