Linux网络编程的套接字分析(其一,基本知识)

套接字的类型

Linux系统的套接字有三类:流套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAM)。

流套接字

用于面向连接的、可靠的数据传输服务。该服务将保证数据能够实现无差别、无重复发送,并按顺序接收。流套接字用于TCP协议。

数据报套接字

提供一种无连接的服务。该服务并不能保证数据的可靠性,数据在传输过程中可能会丢失或重复,且无法保证顺序地接收到数据。一般用于UDP协议,如果要为传输增加可靠性,可以在程序中实现,例如使用kcp协议去封装udp协议。

原始套接字

允许对较低层次的协议直接访问,比如IP、ICMP,它常用于检验新的协议实现,或者访问现有服务中配置的新设备,因为原始套接字可以自如地控制Linux下的多种协议,能够对底层的传输机制进行控制,所以可以应用原始套接字来操控网络层合传输层应用。比如:接收发送发向本机的ICMP、IGMP协议包,或者接收TCP/IP栈不能够处理的IP包,也可以用来发送一些自定义报头或者自定义协议的IP包。网络监听技术经常会用到原始套接字。

总:原始套接字合标准套接字(前两个)的区别在:原始套接字可以读写内核没有处理的IP数据报,而流套接字只能读取TCP的数据,数据报套接字只能读取UDP的数据。

套接字地址

一个套接字嗲表通信的一端,每端都有一个套接字地址,这个socket地址包含了ip地址和端口等信息。有了ip地址便可以区分主机,有了端口号,便可以区分主机上的进程。套接字地址一般分为 通用套接字地址 和 专用套接字地址。
通用socket地址: sockaddr
专用套接字地址:sockaddr_in 和 sockaddr_in6 (分别是IP4和IP6)

获取套接字地址

获取本地套机字地址:getsockname
获取远程套接字地址:getpeername

#incudle <sys/socket.h>
int getsockname(int sockfd, struct sockaddr* localaddr, socklen_t addrlen);
int getpeername(int sockfd, struct sockaddr* peeraddr, socklen_t addrlen);
参数: 套接字描述符, 通用套接字地址结构体(用来存放结果的), 
通用套接字地址结构体的长度,需要使用sizeof(struct sockaddr_in)初始化赋值

例子:获取绑定前后的套接字地址

#include <cstdio>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>

#define PORT 10051
#define SER_IP "192.168.159.129"

int main(){
	int sfp;
	struct sockaddr_in serv = {0};
	serv.sin_port = htons(PORT);
	serv.sin_addr.s_addr = inet_addr(SER_IP);
	serv-sin_family = AF_INET;

	struct sockaddr_in result = {0};
	char on = 1;
	int res_len = sizeof(struct sockaddr_in);
	int err;
	sfp = socket(AF_INET, SOCK_STREAM, 0);
	if( -1 == sfp){
		printf("socket fail\n");
		return -1;
	}
	printf("socket ok\n");
	//打印bind前的socket地址
	printf("ip = %s, port = %d\n", inet_ntoa(result.sin_addr), ntohs(result.sin_port));
	//允许地址立即复用
	setsockopt(sfp, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	
	//打印绑定后的本地套接字地址
	if( -1 == bind(sfp, (struct sockaddr*)(&serv), sizeof(struct sockaddr)) ){
		prinf("bind fail:%d\n");
		return -1;
	}
	printf("bind ok\n");
	getsockname(sfp, (struct sockaddr*)&result, (socklen_t*)&res_len)); 

	printf("ip = %s, port = %d\n", inet_ntoa(result.sin_addr), ntohs(result.sin_port));
	return 0;
}

协议族和地址族

理论上建立socket时,如果是指定协议的,应该使用PF_xxxx,如:PF_INET;如果是指定地址的,应该使用AF_xxxx,如:AF_INET。当然,两者的值是相同的,混用也问题不大。

在Ubuntu20.04下,/usr/include/x86_64-linux-gnu/bits/socket.h中定义了地址族和协议族。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值