socket编程(上)

socket编程(上)

1.网络数据的五元组信息

  • 源ip地址:标识网络数据从哪台主机发出
  • 源端口:标识网络数据从源ip对应的这台主机的哪个进程产生
  • 目的ip:表示网络数据要去哪一台主机
  • 目的端口:通过目的ip找到目的主机之后,通过目的端口找到相应的进程
  • 协议:双方传输数据时,使用什么协议(一般是TCP/IP)

2.网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏
移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?

  • 小端字节序:低位放在低地址
  • 大端字节序:低位放在高地址
  • 主机字节序:指的是机器本身的字节序,如果是大端,则主机字节序为大端。如果是小端,则主机字节序为小端
  • 网络字节序:规定网络传输数据的时候采用大端字节序进行传输

主机字节序和网络字节序的互相转换

主机字节序转换成网络字节序
ip:unint32_t
uint32_t htonl(uint32_t hostlong);
port:uint16_t
uint16_t htons(uint16_t hostshort);
网络字节序转换成主机字节序
ip:unint32_t
uint32_t ntohl(uint32_t hostlong);
port:uint16_t
uint16_t ntohs(uint16_t hostshort);

3.TCP/UDP协议特性与区别

UDP:

  • 无连接:UDP双方在发送数据之前是不需要进行沟通的,只需要知道对方的ip和端口就可以发送
  • 不可靠:不保证UDP数据是可靠、有序的到达对方
  • 面向数据报:UDP和应用层/网络层递交数据时都是整条数据进行交付的

TCP:

  • 面向连接:TCP在发送数据之前会先建立连接(1.确保对方能正常通信。2.沟通双方发送后续数据的细节(例如序号))
  • 可靠传输:TCP保证传输的数据是可靠的、有序的到达对端的
  • 面向字节流:1.对于传输的数据没有传输的边界
    2.对于接收方而言,可以按照1任意的字节进行接收

4.UDP-socket编程

流程:

服务端:创建套接字,绑定地址信息
客户端:创建套接字,不推荐绑定地址信息(可以绑定)

为什么要创建套接字?

将进程和网卡进行绑定,进程可以从网卡中接收数据,也可以通过网卡发送数据

为什么要绑定地址信息?

绑定ip,绑定端口是为了在网络中可以标识出来一台主机和一个进程
对于接收方而言,发送数据的人就知道接收方在哪台主机哪个进程了
对于发送方而言,能够标识网络数据从哪台机器哪个进程发送出去的

5.编程接口

创建套接字:

#include<sys/socket.h>
int socket(int domain,int type,int protocol);

  • domain:地址域-选择一个具体的协议族进行沟通,TCP/UDP,可以认为在指定网络层使用什么协议
    AF_UNIX:本地域套接字(在同一台机器使用文件进行通信,不用跨机器)
    AF_INET:ipv4版本的ip协议
    AF_INET6:ipv版本的IP协议
  • type:套接字的类型
    SOCK_DGRAM:用户数据报套接字-对应UDP
    SOCK_STREAM:流式套接字-对应TCP
  • protocol:协议
    0:表示按照套接字类型选择默认协议
    也可以执行具体的协议:
    IPPROTO_TCP(6):代表TCP协议
    IPPROTO_UDP(17):代表UDP协议
  • 返回值:返回套接字操作句柄,本质上就是一个文件描述符
    大于等于0:创建成功
    小于0:创建失败

绑定接口:

int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);

  • sockfd:套接字描述符
  • addr:绑定的地址信息
  • addrlen:绑定的地址信息长度

发送接口:

ssize_t sendto(int sockfd,const void *buf,size_t len,int flags,const struct sockaddr *deat_addr,socklen_t addrlen);

  • sockfd:套接字描述符
  • buf:要发送的数据
  • len:要发送数据的长度
  • flags:0(阻塞发送)
  • dest_addr:地址信息结构,包含了目的ip,目的端口
  • addrlen:地址信息长度
  • 返回值:成功,返回正常发送的数据;失败,返回-1

接收接口:

ssize_t resvfrom(int sockfd,void *buf,size_t len,int flags,struct sockaddr *src_addr,socklen_t *addrlen);

  • sockfd:套接字描述符
  • buf:程序员准备的接收数据的缓冲区
  • len:最大能接受数据的大小
  • flags:0(阻塞接收)
  • src_addr:源ip+源端口
  • addrlen:这是一个出参,返回地址信息的长度

通用数据结构:

struct sockaddr{
sa_family_t sa_family;//地址域,占用两个字节
char sa_data[14];
};

struct sockaddr_in{
sa_family_t sin_family;//地址族
uint16_t sin_port;//端口号
struct in_addr sin_addr;//32位IP地址
char sin_zero[8];//预留未使用
};

struct in_addr{
In_addr_t s_addr;//32位IPV4地址
};

代码:

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


int main(){
  //1.创建套接字
  int sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
  if(sockfd<0){
    perror("socket");
    return 0;
  }
  printf("sockfd is %d\n",sockfd);

  //2.绑定地址信息
  struct sockaddr_in addr;
  addr.sin_family=AF_INET;
  addr.sin_port=htons(28989);
  //1.将点分十进制的ip转换成无符号的32位整数
  //2.将无符号的32位整数转换成网络字节序
  addr.sin_addr.s_addr=inet_addr("10.0.16.3");

  int ret=bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
  if(ret<0){
    perror("bind");
    return 0;
  }
  while(1){
    sleep(1);
  }
  return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值