网络编程套接字

一、基本概念

接上一篇网络基础(一),我们继续了解网络中的一些基本概念。

1.1 端口(port)

1、端口与传输层息息相关,端口是传输层协议的内容;
2、端口是一个2字节16位的整数,范围是0~65535;
3、端口用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;
4、IP地址 + 端口能够标识网络上的某一台主机的某一个进程;
5、一个端口只能被一个进程占用,一个进程可以占用多个端口。

1.2 五元组

所谓的五元组,就是包括源IP地址、目的IP地址、源端口、目的端口、协议。网络传输当中的数据里,一定是存在五元组信息的,如果缺少五元组信息,则一定不能传输。
示意图:
在这里插入图片描述

1.3 网络字节序

字节序:CPU对内存数据的读取顺序。
大小端字节序
大端:低位保存在高地址;小端:低位保存在低地址
在这里插入图片描述
如何判断当前机器是大端机器还是小端机器呢?
参考之前的文章:判断大小端机器

网络字节序:不管机器是大端机器还是小端机器,在传输的时候都是按照网络字节序进行传输,网络字节序本质上就是大端字节序。
主机字节序:机器本身的字节序(大/小端)

网络传输当中,传输数据时,将主机字节序转换为网络字节序;接收数据时,将网络字节序转换为主机字节序。

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换:

uint32_t htonl(uint32_t hostlong);
//将主机字节序转化成为网络字节序,转化4字节

uint32_t ntohl(uint32_t netlong);
//将网络字节序转化成为主机字节序,转化4字节

uint16_t htons(uint18_t hostshort);
//将主机字节序转化成为网络字节序,转化2字节

uint16_t ntohs(uint16_t netshort);
//将网络字节序转化成为主机字节序,转化2字节

二、socket 编程接口

2.1 socket 常见API

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);

domain:地址域,网络层使用什么协议。其中包含AF_INET:ipv4版本的ip协议;AF_INET6:ipv6版本的协议;AF_UNIX:域套接字
type:套接字的类型。其中包括SOCK_DGRAM:用户数据报套接字,默认协议是UDP协议;SOCK_STREAM:流式套接字,默认的协议是TCP协议
protocol:表示协议。IPPROTO_UDP(17)、IPPROTO_TCP(6)、也可以传递0,表示使用套接字的默认协议。
返回值:套接字描述符,本质上还是一个文件描述符。

// 绑定端口号 (TCP/UDP, 服务器)      
int bind(int sockfd, const struct sockaddr *addr,
         socklen_t addrlen);

sockfd:套接字描述符
addr:地址信息
addrlen:传入的结构体的真实字节数量

//UDP的socket发送接口
ssize_t sendto(int sockfd,const void* buf,size_t len,int flags,const struct sockaddr* dest_addr,socklen_t addrlen);

sockfd:套接字描述符
buf:要发送的内容
len:发送数据的长度
flags:0表示阻塞发送
dest_addr:要将数据发送到哪里去,对端的地址信息
addrlen:地址信息的长度

//UDP的socket接收端口
ssize_t recvfrom(int sockfd,void* buf,size_t len,int flags,struct sockaddr* src_addr,socklen_t* addrlen);

sockfd:套接字描述符
buf:接收数据准备的缓冲区
len:缓冲区接收的最大能力
flags:0表示阻塞接收
src_addr:消息发送端的地址信息,接收回来的消息是从哪里来的
addrlen:输入输出型参数,返回的就是地址信息的真实长度

//TCP发送接口
ssize_t send(int sockfd,const void* buf,size_t len,int flags);

sockfd:套接字描述符,客户端是socket函数的返回值;服务端是为客户端新创建的套接字描述符
buf:待发送的数据
len:发送数据的长度
flags:0表示阻塞发送

//TCP接收端口
ssize_t recv(int sockfd,void* buf,size_t len,int flags);

sockfd:套接字描述符,客户端是socket函数的返回值;服务端是为客户端新创建的套接字描述符
buf:缓冲区,用来接收数据
len:接收的最大能力
flags:0表示阻塞接收
返回值大于0表示接收了多少字节的数据;等于0表示对端断开了连接,意味着对端调用了close;小于0表示接收失败

// 开始监听socket (TCP, 服务器)
// 当调用监听之后,意味着告诉操作系统,当前进程可以接收新的TCP连接了。换句话说,告诉操作系统,当前进程可以开始接收客户端的三次握手请求了
int listen(int sockfd, int backlog);

sockfd:套接字描述符
backlog:已完成连接队列的大小
在这里插入图片描述

//获取连接(TCP,服务器)
int accept(int sockfd,struct sockaddr* addr,socklen_t* addrlen);

sockfd:套接字描述符,传递的是侦听套接字
addr:对端地址信息
addrlen:对端地址信息长度
返回值:返回为新连接创建的套接字描述符

// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

sockfd:套接字描述符
addr:服务端的地址信息
addrlen:地址信息长度

//关闭套接字
close(int sockfd);

sockfd:套接字描述符

2.2 sockaddr结构

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要讲的UNIX DomainSocket. 然而, 各种网络协议的地址格式并不相同。
在这里插入图片描述
1、IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址;
2、IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容;
3、socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数。

三、UDP编程

在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <iostream>

int main()
{
   
    //1.创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sockfd < 0)
    {
   
        perror("socket");
        return -1;
    }
    while(1)
    {
   
        char buf[1024] = {
   0};
        memset(buf, '\0', sizeof(buf));
        std::cin >> buf;
        struct sockaddr_in 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值