tcp/ip:连接服务器失败(错误原因:connection refused)
linux中,通过系统调用(system call) connect 连接指定服务器建立tcp连接。
connect 最常见的失败原因是 connection refused。
假设服务器ip是192.168.44.148,且并 未有 进程监听端口是12500时:
若有tcp连接请求包到达192.168.44.148,则192.168.44.148的内核将 回复rst包 给客户端。
此时,在客户端一侧看来就是connect连接失败,被服务端拒绝连接。
code:
客户端:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
int client_fd = socket(af_inet, sock_stream, 0);
if (client_fd < 0)
{
fprintf(stderr, "create socket error=%d(%s)!!!\n", errno, strerror(errno));
exit(1);
}
struct sockaddr_in server_addr;
server_addr.sin_family = af_inet;
server_addr.sin_port = htons(12500);
if (inet_pton(af_inet, "192.168.44.148", &server_addr.sin_addr) <= 0)
{
fprintf(stderr, "inet_pton error!!!\n");
exit(1);
}
if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
fprintf(stderr, "socket connect error=%d(%s)!!!\n", errno, strerror(errno));
exit(1);
}
fprintf(stdout, "connect to server ok!\n");
close(client_fd); // free connection
return 0;
}
编译:
[jiang@localhost client]$ gcc -o client client.c
[jiang@localhost client]$ ll
total 16
-rwxrwxr-x. 1 jiang jiang 8237 jun 10 09:41 client
-rw-rw-r--. 1 jiang jiang 906 jun 10 09:29 client.c
运行:
服务器主机:
[test1280@localhost ~]$ ifconfig | grep "inet addr"
inet addr:192.168.44.148 bcast:192.168.44.255 mask:255.255.255.0
inet addr:127.0.0.1 mask:255.0.0.0
[test1280@localhost ~]$ netstat -an | grep 12500
客户端主机:
[jiang@localhost client]$ ./client
socket connect error=111(connection refused)!!!
tcpdump抓取协议包:
[root@localhost ~]# tcpdump tcp port 12500 -i eth0 -s 0 -w jiang.cap
tcpdump: listening on eth0, link-type en10mb (ethernet), capture size 65535 bytes
^c2 packets captured
2 packets received by filter
0 packets dropped by kernel
wireshark分析jiang.cap:
1)
客户端调用 connect,发起tcp连接建立请求到服务端。
2)
服务器内核收到要连接本机12500端口的请求,发现并未有对应的监听socket,于是回复rst到客户端。
3)
客户端调用 connect 失败,错误原因:connection refused。
服务器code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define backlog 16
int main()
{
// socket
int listen_fd = socket(af_inet, sock_stream, 0);
if (listen_fd < 0)
{
fprintf(stderr, "create socket error=%d(%s)!!!\n", errno, strerror(errno));
exit(1);
}
int flag = 1;
if (setsockopt(listen_fd, sol_socket, so_reuseaddr, &flag, sizeof(flag)) < 0)
{
fprintf(stderr, "socket setsockopt error=%d(%s)!!!\n", errno, strerror(errno));
exit(1);
}
// bind
struct sockaddr_in server_addr;
server_addr.sin_family = af_inet; // ipv4
server_addr.sin_port = htons(12500); // port
server_addr.sin_addr.s_addr = htonl(inaddr_any); // ip
if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
fprintf(stderr, "socket bind error=%d(%s)!!!\n", errno, strerror(errno));
exit(1);
}
// listen
if (listen(listen_fd, backlog) < 0)
{
fprintf(stderr, "socket listen error=%d(%s)!!!\n", errno, strerror(errno));
exit(1);
}
fprintf(stdout, "server init ok, start to accept new connect...\n");
// accept
int client_fd = accept(listen_fd, null, null);
if (client_fd < 0)
{
fprintf(stderr, "socket accept error=%d(%s)!!!\n", errno, strerror(errno));
exit(1);
}
fprintf(stdout, "accept one new connect!!!\n");
char msg[1024] = "";
// read client-fin=1 eof
while (read(client_fd, msg, sizeof(msg)-1) == 0)
break;
close(client_fd);
return 0;
}
编译:
[test1280@localhost server]$ gcc -o server server.c
[test1280@localhost server]$ ll
total 16
-rwxrwxr-x. 1 test1280 test1280 9616 jun 10 09:51 server
-rw-r--r--. 1 test1280 test1280 1555 jun 10 09:50 server.c
运行:
[test1280@localhost server]$ ./server
server init ok, start to accept new connect...
accept one new connect!!!
[test1280@localhost ~]$ ifconfig | grep "inet addr"
inet addr:192.168.44.148 bcast:192.168.44.255 mask:255.255.255.0
inet addr:127.0.0.1 mask:255.0.0.0
[test1280@localhost ~]$ netstat -an | grep 12500
tcp 0 0 0.0.0.0:12500 0.0.0.0:* listen
[jiang@localhost client]$ ./client
connect to server ok!
即使当前主机有进程监听12500端口,connect依然有可能被拒绝连接
略微修改下服务器代码(不使用地址通配inaddr_any):
// bind
struct sockaddr_in server_addr;
server_addr.sin_family = af_inet;
server_addr.sin_port = htons(12500); // port
// if (inet_aton("0.0.0.0", &(server_addr.sin_addr)) != 1)
// if (inet_aton("192.168.44.148", &(server_addr.sin_addr)) != 1)
if (inet_aton("127.0.0.1", &(server_addr.sin_addr)) != 1)
{
fprintf(stderr, "inet_aton error!!!\n");
exit(1);
}
if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
fprintf(stderr, "socket bind error=%d(%s)!!!\n", errno, strerror(errno));
exit(1);
}
编译 && 运行:
[test1280@localhost server]$ gcc -o server server.c
[test1280@localhost server]$ ll
total 16
-rwxrwxr-x. 1 test1280 test1280 9620 jun 10 10:12 server
-rw-r--r--. 1 test1280 test1280 1737 jun 10 10:12 server.c
[test1280@localhost server]$ ./server
server init ok, start to accept new connect...
[test1280@localhost ~]$ ifconfig | grep "inet addr"
inet addr:192.168.44.148 bcast:192.168.44.255 mask:255.255.255.0
inet addr:127.0.0.1 mask:255.0.0.0
[test1280@localhost ~]$ netstat -an | grep 12500
tcp 0 0 127.0.0.1:12500 0.0.0.0:* listen
此时,在服务器上虽然有进程监听12500端口,但是监听套接字的ip地址是127.0.0.1(在127.0.0.1地址上监听12500端口)。
如果我们在客户端主机(192.168.44.144)上向【192.168.44.148:12500】发起tcp连接请求,将会被拒绝:
[jiang@localhost client]$ ifconfig | grep "inet addr"
inet addr:192.168.44.144 bcast:192.168.44.255 mask:255.255.255.0
inet addr:127.0.0.1 mask:255.0.0.0
[jiang@localhost client]$ ./client
socket connect error=111(connection refused)!!!
被拒绝原因是在148服务器上不存在监听套接字【192.168.44.148:12500】,只有监听套接字【127.0.0.1:12500】。
如果我们在服务端主机(192.168.44.148)上向【127.0.0.1:12500】发起tcp连接请求,将会被允许:
修改客户端代码:
struct sockaddr_in server_addr;
server_addr.sin_family = af_inet;
server_addr.sin_port = htons(12500);
if (inet_pton(af_inet, "127.0.0.1", &server_addr.sin_addr) <= 0)
{
fprintf(stderr, "inet_pton error!!!\n");
exit(1);
}
编译 && 运行:
[test1280@localhost client]$ ifconfig | grep "inet addr"
inet addr:192.168.44.148 bcast:192.168.44.255 mask:255.255.255.0
inet addr:127.0.0.1 mask:255.0.0.0
[test1280@localhost client]$ gcc -o client client.c
[test1280@localhost client]$ ./client
connect to server ok!