linux socket通讯如何获取本地的源端口号

原创 2017年09月24日 19:14:48
关于TCP IP网络通讯的资料非常多,TCP IP通过IP数据包模式进行端对端通讯。典型的TCP数据包如下

可以看到数据包包含了源端口号和目的端口号,客户端socket向服务端发起连接时,系统会给socket随机分配一个源端口号,我们可以通过getsocketname来获取连接成功的socket的原端口信息。
函数原型
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
sockfd socket连接的句柄
addr 网络地址指针,用来存储本地端socket地址信息,
addrlen addr的空间大小
返回结果,如果调用成功,返回0,并将本地网络地址信息存放在addr里面,失败返回-1,并通过errno反应错误信息。
source_port.cpp
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>

void safe_close(int &sock);

int main(int argc, char *argv[]) {
	int sockfd = 0, n = 0;
	socklen_t len = 0;
	char host[512] = {0};
	char buf[1024] = {0};
	struct hostent *server;
	struct sockaddr_in serv_addr, loc_addr;

	if (argc < 2) {
		printf("Please input host name\n");
		exit(-1);
	}
    strncpy(host, argv[1], sizeof(host));
    server = gethostbyname(host);// 判断输入的域名是否正确
	if (NULL == server) {
		printf("find host: %s failed.\n", host);
		exit(-1);
	}

	if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0))) {// 创建socket
		memset(buf, 0, sizeof(buf));
		snprintf(buf, sizeof(buf), "new socket failed. errno: %d, error: %s", errno, strerror(errno));
		perror(buf);
		exit(-1);
	}

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(80);// http标准端口号
	memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);

	if (-1 == inet_pton(AF_INET, host, &serv_addr.sin_addr)) {
		memset(buf, 0, sizeof(buf));
		snprintf(buf, sizeof(buf), "inet_pton failed. errno: %d, error: %s", errno, strerror(errno));
		perror(buf);
		exit(-1);
	}

	if (-1 == connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) {// 连接socket
		memset(buf, 0, sizeof(buf));
		snprintf(buf, sizeof(buf), "connect socket failed. errno: %d, error: %s", errno, strerror(errno));
		perror(buf);
		exit(-1);
	}
	printf("connect to %s success.\n", host);

	len = sizeof(sizeof(loc_addr));
	memset(&loc_addr, 0, len);
	if (-1 == getsockname(sockfd, (struct sockaddr *)&loc_addr, &len)) {// 获取socket绑定的本地address信息
		memset(buf, 0, sizeof(buf));
		snprintf(buf, sizeof(buf), "get socket name failed. errno: %d, error: %s", errno, strerror(errno));
		perror(buf);
		safe_close(sockfd);
		exit(-1);
	}

	if (loc_addr.sin_family == AF_INET) {// 打印信息
		printf("local port: %u\n", ntohs(loc_addr.sin_port));
	}

	safe_close(sockfd);
	return 0;
}

void safe_close(int &sock) {
	if (-1 != sock) {
		shutdown(sock, SHUT_RDWR);
		sock = -1;
	}
}
本程序首先会启动一个socket连接一个普通的http服务器(baidu,qq,163,csdn),当socket连通时就通过getsocketname获取连接绑定的本地地址,并通过该地址获取源端口号。
终端1: 编译及运行
$ g++ source_port.cpp
$ ./a.out www.baidu.com
connect to www.baidu.com success.
local port: 39702
终端2: 通过tcpdump抓包验证
$ sudo tcpdump host www.baidu.com -v
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
18:38:32.381448 IP (tos 0x0, ttl 64, id 35033, offset 0, flags [DF], proto TCP (6), length 60)
icentos.39702 > 220.181.111.188.http: Flags [S], cksum 0x8cd2 (incorrect -> 0x596a), seq 2381397554, win 29200, options [mss 1460,sackOK,TS val 3513497323 ecr 0,nop,wscale 7], length 0
18:38:32.425904 IP (tos 0x0, ttl 55, id 35033, offset 0, flags [DF], proto TCP (6), length 60)
220.181.111.188.http > icentos.39702: Flags [S.], cksum 0xc315 (correct), seq 3561856904, ack 2381397555, win 8192, options [mss 1424,sackOK,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,wscale 5], length 0
18:38:32.425930 IP (tos 0x0, ttl 64, id 35034, offset 0, flags [DF], proto TCP (6), length 40)

对比终端一和终端二表明获取的源端口地址是正确的。

socket通信关于bind端口和IP

结论: 1、采用TCP通信时,客户端不需要bind()他自己的IP和端口号,而服务器必须要bind()自己本机的IP和端口号; 2、若采用UDP通信时(这里是有客户端和服务器之分才这么说的,若是指...
  • wu_wenhuan
  • wu_wenhuan
  • 2015年05月11日 10:53
  • 5685

android实现socket端口通信demo

android实现socket端口通信demo (1)socket通信描述 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信。两者的最大差异在于,http连接使 ...
  • u012255016
  • u012255016
  • 2016年07月08日 14:39
  • 2369

通过网络socket获取对方 ip 和port

定义 int getpeername(int s, struct sockaddr *name, socklen_t *namelen); 描述 获取socket的对方地址 ...
  • zhengfl
  • zhengfl
  • 2014年03月24日 18:31
  • 7831

同wifi环境下android设备自动获取socket服务端的ip地址和端口号的方法-UDP广播

一、最近做项目,需要使用socket做一个常连接,实现实时通信,但是需求是在同一个wifi环境下,ip地址是动态获取的,这样就造成了服务端地址的不确定性。解决这个问题的关键就是如何拿到服务端的Ip。我...
  • suyiyang888
  • suyiyang888
  • 2014年03月18日 10:44
  • 3154

Linux获取指定端口服务信息,获取指定服务器端口号

  • 2015年12月04日 12:35
  • 4KB
  • 下载

linux下获取进程网络链接状况(包括打开的侦听端口号)

在做一个本地服务(服务器端和客户端在同一个机器上,通过回环端口直接访问)时,因为端口可能会被其他程序占用,服务器端会尝试找到一个可用端口,客户端需要逐个尝试连接各个端口,并且与服务器端完成一个验证过程...
  • luansxx
  • luansxx
  • 2012年07月24日 17:22
  • 5436

公认协议号,预分配协议号和端口号文档(取自linux)

  • 2012年11月12日 17:36
  • 10KB
  • 下载

LWIP UDP socket编程 可以指定本地端口号及发送长度不能太长问题分析

发送方: /*   * File:   main.c  * Author: tianshuai  *  * Created on 2011年11月29日, 下午10:34  *  * 主要实现:发...
  • hexiechina2010
  • hexiechina2010
  • 2016年03月01日 17:02
  • 1635

JAVA基础再回首(二十八)——网络编程概述、IP地址、端口号、TCP和UDP协议、Socket、UDP传输、多线程UDP聊天

JAVA基础再回首(二十八)——网络编程概述、IP地址、端口号、TCP和UDP协议、Socket、UDP传输、多线程UDP聊天 版权声明:转载必须注明本文转自程序员杜鹏程的博客:http://bl...
  • m366917
  • m366917
  • 2016年10月02日 15:32
  • 2185

c语言打开文件方式 socket 端口号

mode有以下几种方式: 打开方式 说明 r 以只读方式打开文件,该文件必须存在。 r+ 以读/写方式打开文件,该文件必须存在。 rb+ 以读/写方式打开一个二进制文件,只允许读/写数据。 rt+ 以...
  • heroyiuyiu
  • heroyiuyiu
  • 2016年08月24日 10:55
  • 535
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux socket通讯如何获取本地的源端口号
举报原因:
原因补充:

(最多只允许输入30个字)