您的位置:首页 > 理论基础 > 计算机网络

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

2017-04-27 14:52 417 查看
在很多情况下,我们需要使用固定的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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐