在rtthread系统测试socket server时发现首次启动可以绑定成功,再次启动时会bind失败,网上提到几种方法:SO_REUSEADDR、 SO_REUSEPORT 、SO_LINGER。尝试之后发现调用函数都失败了。
查看LWIP源码发现有 LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT、LWIP_SO_LINGER、SO_REUSE三处定义比较可疑,然后直接在编译LWIP源码时在makefile文件中加上-DSO_REUSE=1 -DLWIP_SO_LINGER=1后,SO_REUSEPORT 依旧失败,但是SO_REUSEADDR以及SO_LINGER成功了。再次启动socket server时也可以正常绑定了。
我最终只用了-DSO_REUSE=1,然后测试代码中调用lwip_setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int))达到了预期效果。
/*************************************************************************
> File Name: client.c
> Author:
> Mail:
> Created Time: 2019年09月20日 星期五 17时20分55秒
************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <log.h>
#include "bcm_wifi.h"
#include "lwip/tcpip.h"
//#include <utils/plat_log.h>
//#define LOG_TAG "dong_client"
static int cmd_dong_client(int argc, char ** argv[])
{
int i = 0;
struct sockaddr_in serv_addr;
int sock = 0;
char server_ip[20];
int port = 0;
char msg_buffer[1024];
int ret = 0;
memset(server_ip, 0, sizeof(server_ip));
memset(&serv_addr, 0, sizeof(serv_addr));
if(argc < 3){
printk("Usage: dong_client server_ip port\n");
printk("\tdong_client 192.168.19.199 8888\n");
return -1;
}else{
memcpy(server_ip, argv[1], strlen(argv[1]));
port = strtol(argv[2], NULL, 0);
printk("server_ip:%s, port:%d\n", server_ip, port);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(server_ip);
serv_addr.sin_port = htons(port);
sock = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);//IPPROTO_IP 0, IPPROTO_TCP 6
if(sock == -1){
printk("socket failed\n");
return -1;
}
if(lwip_connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) != 0){
printk("connect failed\n");
goto _exit;
}
{
struct sockaddr_in serv, guest;
socklen_t serv_len = sizeof(serv);
socklen_t guest_len = sizeof(guest);
lwip_getsockname(sock, &guest, &guest_len);
lwip_getpeername(sock, &serv, &serv_len);
printk("guest addr:%s, port:%d\n", inet_ntoa(guest.sin_addr.s_addr), ntohs(guest.sin_port));
printk("server addr:%s, port:%d\n", inet_ntoa(serv.sin_addr.s_addr), ntohs(serv.sin_port));
}
memset(msg_buffer, 0, sizeof(msg_buffer));
sprintf(msg_buffer, "dong_socket\n");
ret = lwip_write(sock, msg_buffer, strlen(msg_buffer));
printk("lwip_write ret = %d, %s\n", ret, msg_buffer);
if (ret == -1){
printf("lost connection\n");
goto _exit;
}
while(1){
i++;
memset(msg_buffer, 0, sizeof(msg_buffer));
ret = lwip_read(sock, msg_buffer, sizeof(msg_buffer)-1);
printk("\n---------------------------\n");
printk("lwip_read ret = %d, %s\n", ret, msg_buffer);
if (ret == -1){
printf("lost connection\n");
goto _exit;
}
ret = lwip_write(sock, msg_buffer, strlen(msg_buffer));
printk("lwip_write ret = %d, %s\n", ret, msg_buffer);
if (ret == -1){
printf("lost connection\n");
goto _exit;
}
if(strcmp(msg_buffer, "quit") == 0){
printk("Bye!\n");
break;
}
sleep(1);
}
_exit:
printk("close socket\n");
//close(sock);
lwip_close(sock);
printk("---------------dong_client exit---------------\n");
return 0;
}
FINSH_FUNCTION_EXPORT_ALIAS(cmd_dong_client, __cmd_dong_client, socket client test);
int cmd_dong_server(int argc, char ** argv[])
{
int ret = 0;
int serv_sock = 0;
int clnt_sock = 0;
struct sockaddr_in serv_addr;
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
int port = 0;
char msg_buffer[1024];
if(argc < 2){
printk("Usage: dong_server port\n");
printk("\tdong_server 8888\n");
return -1;
}else{
port = strtol(argv[1], NULL, 0);
printk("port:%d\n", port);
}
memset(&serv_addr, 0, sizeof(serv_addr));
#if 0
uint8_t server_ip_bytes[4];
extern void mhd_sta_dhcpc_get_ip_address(char *);
mhd_sta_dhcpc_get_ip_address(server_ip_bytes);
printf("mhd_sta_dhcpc_get_ip_address: %d.%d.%d.%d\n", server_ip_bytes[0], server_ip_bytes[1], server_ip_bytes[2], server_ip_bytes[3]);
memset(msg_buffer, 0, sizeof(msg_buffer));
sprintf(msg_buffer, "%d.%d.%d.%d", server_ip_bytes[0], server_ip_bytes[1], server_ip_bytes[2], server_ip_bytes[3]);
serv_addr.sin_addr.s_addr = inet_addr(msg_buffer);
#else
serv_addr.sin_addr.s_addr = INADDR_ANY;//htonl(INADDR_ANY);
#endif
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_sock = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);//IPPROTO_IP 0, IPPROTO_TCP 6
if(serv_sock == -1){
printk("socket failed\n");
return -1;
}
#if 1
int on = 1;
//try to fix bug when server restart, bind would fail, must define SO_REUSE when compile lwip!!!
if(lwip_setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) != 0){
printk("setsockopt SO_REUSEADDR failed\n");
//goto _exit_server;
}
on = 1;
if(lwip_setsockopt(serv_sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int)) != 0){
printk("setsockopt SO_REUSEPORT failed\n");
//goto _exit_server;
}
//#else
//must define LWIP_SO_LINGER when compile lwip!!!
struct linger so_linger;
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
if(lwip_setsockopt(serv_sock, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger)) != 0){
printk("setsockopt SO_LINGER failed\n");
//goto _exit_server;
}
#endif
ret = lwip_bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if(ret != 0){
printk("bind failed\n");
goto _exit_server;
}
ret = lwip_listen(serv_sock, 20);
if(ret != 0){
printk("listen failed\n");
goto _exit_server;
}
clnt_sock = lwip_accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if(clnt_sock == -1){
printk("accept failed\n");
goto _exit_server;
}else{
printk("client addr:%s, port:%d\n", inet_ntoa(clnt_addr.sin_addr.s_addr), ntohs(clnt_addr.sin_port));
}
{
struct sockaddr_in serv, guest;
socklen_t serv_len = sizeof(serv);
socklen_t guest_len = sizeof(guest);
lwip_getsockname(clnt_sock, &serv, &serv_len);
lwip_getpeername(clnt_sock, &guest, &guest_len);
printk("guest addr:%s, port:%d\n", inet_ntoa(guest.sin_addr.s_addr), ntohs(guest.sin_port));
printk("server addr:%s, port:%d\n", inet_ntoa(serv.sin_addr.s_addr), ntohs(serv.sin_port));
}
memset(msg_buffer, 0, sizeof(msg_buffer));
sprintf(msg_buffer, "dong_server\n");
ret = lwip_write(clnt_sock, msg_buffer, strlen(msg_buffer));
printk("lwip_write ret = %d, %s\n", ret, msg_buffer);
if (ret == -1){
printf("lost connection\n");
goto _exit_client;
}
while(1){
memset(msg_buffer, 0, sizeof(msg_buffer));
ret = lwip_read(clnt_sock, msg_buffer, sizeof(msg_buffer)-1);
printk("\n---------------------------\n");
printk("lwip_read ret = %d, %s\n", ret, msg_buffer);
if (ret == -1){
printf("lost connection\n");
goto _exit_client;
}
ret = lwip_write(clnt_sock, msg_buffer, strlen(msg_buffer));
printk("lwip_write ret = %d, %s\n", ret, msg_buffer);
if (ret == -1){
printf("lost connection\n");
goto _exit_client;
}
if(strcmp(msg_buffer, "quit") == 0){
printk("Bye!\n");
break;
}
sleep(1);
}
_exit_client:
printk("shutdown socket client\n");
lwip_shutdown(clnt_sock, SHUT_RDWR);
printk("close socket client\n");
lwip_close(clnt_sock);
_exit_server:
printk("shutdown socket server\n");
lwip_shutdown(serv_sock, SHUT_RDWR);
printk("close socket server\n");
lwip_close(serv_sock);
printk("---------------dong_server exit---------------\n");
return 0;
}
FINSH_FUNCTION_EXPORT_ALIAS(cmd_dong_server, __cmd_dong_server, socket server test);
网友评论