无法连接Docker容器中运行的SCTP服务器问题求助
SCTP服务器容器化后连接超时问题排查
问题背景
使用Dockerfile将SCTP服务器容器化后,宿主机客户端向容器内服务器发送请求时出现连接超时,tcpdump显示无数据包到达服务器。
Dockerfile
FROM ubuntu:20.04 # Install utilities RUN apt update && apt install -y libsctp-dev iputils-ping net-tools curl gcc tcpdump vim RUN mkdir -p /root/my_proj/ COPY . /root/my_proj/ WORKDIR /root/my_proj/ RUN gcc sctpserver.c -o server -lsctp CMD ["./server"]
相关命令输出
容器状态
/home/ubuntu>sudo docker ps -a | grep sha f99817f89f26 learnsha "./server" 59 minutes ago Up 59 minutes 0.0.0.0:62324->62324/sctp, :::62324->62324/sctp learnsha-pr
客户端运行结果
/home/ubuntu>./client Enter data to send: abc --------> client is hung on host machine Connection failed connect(): Connection timed out
宿主机netstat输出
/home/ubuntu>netstat -n | grep 62324 sctp :::62324 LISTEN sctp 0.0.0.0:62324 LISTEN sctp 0 0 127.0.0.1:50638 127.0.0.1:62324 CLOSE -> why client connect is closed? /home/ubuntu>
代码实现
SCTP服务器代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <time.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <netinet/sctp.h> #define MAX_BUFFER 1024 #define MY_PORT_NUM 62324 /* This can be changed to suit the need and should be same in server and client */ int main () { int listenSock, connSock, ret, in, flags, i; struct sockaddr_in servaddr; struct sctp_initmsg initmsg; struct sctp_event_subscribe events; struct sctp_sndrcvinfo sndrcvinfo; char buffer[MAX_BUFFER + 1]; listenSock = socket (AF_INET, SOCK_STREAM, IPPROTO_SCTP); if(listenSock == -1) { printf("Failed to create socket\n"); perror("socket()"); exit(1); } bzero ((void *) &servaddr, sizeof (servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl (INADDR_ANY); servaddr.sin_port = htons (MY_PORT_NUM); ret = bind (listenSock, (struct sockaddr *) &servaddr, sizeof (servaddr)); if(ret == -1 ) { printf("Bind failed \n"); perror("bind()"); close(listenSock); exit(1); } /* Specify that a maximum of 5 streams will be available per socket */ memset (&initmsg, 0, sizeof (initmsg)); initmsg.sinit_num_ostreams = 5; initmsg.sinit_max_instreams = 5; initmsg.sinit_max_attempts = 4; ret = setsockopt (listenSock, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof (initmsg)); if(ret == -1 ) { printf("setsockopt() failed \n"); perror("setsockopt()"); close(listenSock); exit(1); } ret = listen (listenSock, 5); if(ret == -1 ) { printf("listen() failed \n"); perror("listen()"); close(listenSock); exit(1); } while (1) { char buffer[MAX_BUFFER + 1]; int len; //Clear the buffer bzero (buffer, MAX_BUFFER + 1); printf ("Awaiting a new connection\n"); connSock = accept (listenSock, (struct sockaddr *) NULL, (int *) NULL); if (connSock == -1) { printf("accept() failed\n"); perror("accept()"); close(connSock); continue; } else { printf ("New client connected....\n"); } in = sctp_recvmsg (connSock, buffer, sizeof (buffer), (struct sockaddr *) NULL, 0, &sndrcvinfo, &flags); if( in == -1) { printf("Error in sctp_recvmsg\n"); perror("sctp_recvmsg()"); close(connSock); continue; } else { //Add '\0' in case of text data buffer[in] = '\0'; printf (" Length of Data received: %d\n", in); printf (" Data : %s\n", (char *) buffer); } close (connSock); } return 0; }
SCTP客户端代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <netinet/sctp.h> #include <arpa/inet.h> #define MAX_BUFFER 1024 #define MY_PORT_NUM 62324 /* This can be changed to suit the need and should be same in server and client */ int main (int argc, char* argv[]) { int connSock, in, i, ret, flags; struct sockaddr_in servaddr; struct sctp_status status; char buffer[MAX_BUFFER + 1]; int datalen = 0; /*Get the input from user*/ printf("Enter data to send: "); fgets(buffer, MAX_BUFFER, stdin); /* Clear the newline or carriage return from the end*/ buffer[strcspn(buffer, "\r\n")] = 0; /* Sample input */ //strncpy (buffer, "Hello Server", 12); //buffer[12] = '\0'; datalen = strlen(buffer); connSock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); if (connSock == -1) { printf("Socket creation failed\n"); perror("socket()"); exit(1); } bzero ((void *) &servaddr, sizeof (servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons (MY_PORT_NUM); servaddr.sin_addr.s_addr = inet_addr ("127.0.0.1"); ret = connect (connSock, (struct sockaddr *) &servaddr, sizeof (servaddr)); if (ret == -1) { printf("Connection failed\n"); perror("connect()"); close(connSock); exit(1); } ret = sctp_sendmsg(connSock, (void *) buffer, (size_t) datalen, NULL, 0, 0, 0, 0, 0, 0); if(ret == -1 ) { printf("Error in sctp_sendmsg\n"); perror("sctp_sendmsg()"); } else { printf("Successfully sent %d bytes data to server\n", ret); } close (connSock); return 0; }
排查方向
- 检查宿主机SCTP模块加载状态:执行
lsmod | grep sctp,若未加载则运行modprobe sctp启用模块,SCTP依赖内核模块支持,未加载会导致数据包无法处理。 - 验证容器内服务器监听状态:进入容器执行
ss -anp | grep sctp或netstat -n | grep 62324,确认服务器进程是否真的在监听62324端口的SCTP套接字。 - 检查Docker网络对SCTP的支持:Docker 1.12及以上版本支持SCTP,但需宿主机内核支持。启动容器时尝试添加
--cap-add NET_ADMIN权限,部分环境下SCTP转发需要额外权限。 - 排查防火墙/iptables规则:检查宿主机iptables是否有阻止SCTP数据包的规则,执行
iptables -L -n | grep sctp查看相关规则,必要时添加允许SCTP流量的规则。 - 测试容器内本地连接:在容器内部编译运行客户端,连接127.0.0.1:62324,确认服务器本身功能正常,排除代码逻辑问题。
内容的提问来源于stack exchange,提问作者myquest5 sh
相关产品推荐
相关产品推荐

