[摘抄-Socket-学习中]TCP&UDP通信中socket端口的复用

在很多情况下,我们需要使用固定的IP和端口号进行通信,而默认情况下client端的端口号是不固定的,是由系统自动分配空闲的端口号进行通信的;

但是在很多情况下,某些服务写的比较严格,只接收固定的IP和端口号的数据,大家都知道IP地址我们是可以保证不变的,但是端口号在默认情况下是不可能实现不变的,这个时候我们就需要对端口号进行特殊处理;

想到要端口号固定,默认我们就想到了使用bind函数绑定端口号进行数据通信,想法是对的,但是我们实际写出代码进行测试的时候发现错了;

bind不能和服务端绑定同一个IP和端口号,但是可以绑定不通的端口号然后进行发送,这个时候就真的实现了client端固定IP和端口号发送数据,那么问题来了,我们怎么去实现和监听服务使用同一个IP和端口号呢?如何让bind在监听端和发送端同时生效呢?

百度了下有关socket通信中端口号的一些知识,发现了一个特殊的字眼“复用”,没错socket中是可以对IP地址和端口号进行复用的,也就是监听和发送使用同一个IP和端口号;

找到了资料开始百度如何去复用端口号操作,查到了一个关键函数:setsockopt

具体有何意义,可以自行百度下此函数的使用,另外需要注意下,IP和端口号复用的参数是:SO_REUSEADDR

注意:监听和发送的时候必须同时使用setsockopt 这个函数方有效;

UDP服务监听示例代码:

static void* Create_UdpServer_Tread(void *point)
{
int sockfd;
int len;
int recvLen;
unsigned char buf[BUF_SIZE];
char log[BUF_SIZE];
char temp[8];
struct sockaddr_in adr_inet;
struct sockaddr_in adr_clnt;
bzero(&adr_inet, sizeof(adr_inet));
adr_inet.sin_family = AF_INET;
if(strcmp(SERVER_IP,(char*)"NULL") == 0 || strlen(SERVER_IP) <= 0)
{
adr_inet.sin_addr.s_addr = htonl(INADDR_ANY);
} else {
adr_inet.sin_addr.s_addr = inet_addr(SERVER_IP);
}
adr_inet.sin_port = htons(atoi(SERVER_PORT));
len = sizeof(adr_clnt);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
{
memset(log,0,sizeof(log));
sprintf(log,"UDP socket init fail! sockfd=%d\n",sockfd);
Printflog(log,1);
return NULL;
}else{
memset(log,0,sizeof(log));
sprintf(log,"UDP socket init success! sockfd=%d\n",sockfd);
Printflog(log,0);
}
bool bReuseaddr = true;
int optret=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&bReuseaddr,sizeof(&bReuseaddr));
if(optret!=0)
{
return NULL;
}
int ret = bind(sockfd, (struct sockaddr *)&adr_inet, sizeof(adr_inet));
if(ret == -1)
{
memset(log,0,sizeof(log));
sprintf(log,"UDP socket bind fail! sockfd=%d\n",sockfd);
Printflog(log,1);
return NULL;
} else {
memset(log,0,sizeof(log));
sprintf(log,"UDP socket bind success! sockfd=%d\n",sockfd);
Printflog(log,0);
}
while(1)
{
recvLen = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&adr_clnt, (socklen_t *)&len);
if(recvLen < 0)
{
usleep(100);
continue;
}
char* clientIp = inet_ntoa(adr_clnt.sin_addr);
long clientPort = ntohs(adr_clnt.sin_port);
memset(log, 0, sizeof(log));
sprintf(log, "UDP clientIp=%s,clientPort=%d,recvLen=%d,recvDate=",clientIp, clientPort,recvLen);
for(int i=0; i<recvLen;i++)
{
memset(temp, 0, sizeof(temp));
sprintf(temp, "%02X ",buf[i]);
strcat(log, temp);
}
strcat(log, "\n");
if(strcmp(CLIENT_PORT, (char*)"NULL") != 0)
{
clientPort = atoi(CLIENT_PORT);
}
CheckRecvInfo(buf, recvLen, -1, clientIp, clientPort, (char*)"UDP");
usleep(10);
}
close(sockfd);
return NULL;
}

UDP发送端示例代码:
int SendDataByUdp(char* clientIp, int clientPort, int serverPort, unsigned char* msg, int len)
{
int sockfd;
int result = 0;
struct sockaddr_in adr_srvr, adr_client;
bzero(&adr_srvr, sizeof(adr_srvr));
adr_srvr.sin_family = AF_INET;
adr_srvr.sin_addr.s_addr = inet_addr(clientIp);
adr_srvr.sin_port = htons(clientPort);
adr_client.sin_family = AF_INET;
adr_client.sin_addr.s_addr = htonl(INADDR_ANY);
adr_client.sin_port = htons(serverPort);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
{
return -2;
}
bool bReuseaddr = true;
int optret=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&bReuseaddr,sizeof(&bReuseaddr));
if(optret!=0)
{
return -3;
}
int ret=bind(sockfd, (struct sockaddr *)&adr_client, sizeof(adr_client));
if(ret<0) {
return -4;
}
result = sendto(sockfd, msg, len, 0, (struct sockaddr*)&adr_srvr, sizeof(adr_srvr));
if(result >= 0)
{
close(sockfd);
}
return result;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lock颠颠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值