美文网首页
socket 编程基础

socket 编程基础

作者: 夜殇丶夜逝 | 来源:发表于2016-03-18 12:23 被阅读144次

TCP 服务器的工作流程:

  1. 服务器调用 socket() 创建 socket;
  2. 服务器调用 bind() 绑定端口和 ip;
  3. 服务器调用 listen() 设置缓冲区;
  4. 服务器调用 accept() 接收客户端的连接请求建立连接, 生成一个新的 socket;
  5. 服务器与客户端建立好连接之后, 就可以通过 send()/recv() 向客户端发送或者接收客户端的数据;
  6. 服务器调用 close() 关闭 socket.

客户端工作流程:

  1. 客户端调用 socket() 创建 socket;
  2. 客户端调用 connect() 向服务器发去连接请求以建立连接;
  3. 客户端与服务器建立连接之后, 就可以通过 send()/recv() 向服务器发送或者接收服务器的数据;
  4. 客户端调用 clos() 关闭 socket.
 /**
 *  创建并初始化 socket, 返回该 socket 的文件描述符, 若描述符为 -1 表示创建失败.
 参数:
 addressFamily: 是 IPv4(AF_INET)或者 IPv6(AF_INET6).
 type:          表示 socket 的类型, 通常是流(SOCK_STREAM)或者数据报文(SOCK_DGRAM).
 protocol:      通常为0, 以便让系统自动选择合适的协议,对于 SOCK_STREAM 来说会是 TCP 协议,对于 SOCK_DGRAM 来说会是 UDP 协议
 */
int socket(int addressFamily, int type, int Protocol);

        
/**
 *  关闭 socket
 */
int close(int socketFileDescriptor);
   
        
/**
 *  将 socket 与特定主机地址和端口号绑定,绑定成功返回0, 失败返回 -1;
 绑定成功后可进行不同的操作:
 UDP: 因为 UDP 是无连接的, 绑定之后就可以利用 UDP socket 来传数据了.
 TCP: TCP 是需要建立端到端连接的, 为了建立 TCP 连接, 服务器必须调用 listen(int socketFileDescriptor, int backlogSize)来设置服务器的缓冲区队列以接收客户端的连接请求, backlogSize 表示客户端连接请求缓冲区队列的大小. 当调用 listen 设置之后, 服务端等待客户端请求, 然后调用 listen 设置 accept 来接收客户端的连接请求.
 *
 *  @param socketFileDescriptor  socket 描述文件
 *  @param addressToBind        主机地址
 *  @param addressStructLength  主机地址结构体的长度
 */
int bind((int)socketFileDescriptor, (const struct sockaddr *)&addressToBind, (socklen_t)addressStructLength);
        

/**
 *  接受客户端连接请求并将客户端的网络地址信息保存到 childAddress 中.
 当客户端请求被服务器接受之后, 客户端和服务器之间的连接就建立了, 两者之间就可以通信了.
 注意 accept 会阻塞当前线程, 知道有客户端请求连接进来之后才会继续往下执行.
 *
 *  @param socketFileDescriptor socket 描述字
 *  @param restrict             客户端结构体地址
 *  @param restrict             客户端结构体长度地址
 *
 */
int newSocker = accept((int)socketFileDescriptor, (struct sockaddr *)&childAddress, (socklen_t *restrict)childAddressLength);
   
        
/**
 *  客户端向特定网络地址服务器发送连接请求, 连接成功后返回0, 失败返回 -1;
 当服务器建立好后, 客户端通过调用该接口向服务器发起建立连接请求. 对于 UDP 来说, 该接口是可选的, 如果调用了该接口, 表明设置了该 UDP socket 默认的网络地址. 对 TCP 来说, 这就是传说中三次握手发生的地方.
 
 注意这个接口会阻塞当前线程, 直到服务器返回信息.
 
 *  @param socketFileDescriptor socket 描述字
 *  @param serverAddress        服务器的网络地址
 *
 */
int ss = connect(int socketFileDescriptor, (const struct sockaddr *)&serverAddress, (socklen_t)serverAddressLength);
        
        
/**
 *  使用 DNS 查找特定主机名地址对应的 IP 地址, 如果找不到对应的 IP 地址 则返回 NULL.
 */
int gethostname((char *)&hostName, sizeof(host_name_t));

        
/**
 *  通过 socket 发送数据, 发送成功返回发送的字节数, 否则返回 -1;
 一旦连接建立好之后, 就可以通过 send/recv 接口发送或者接受数据了. 注意, 调用 connect 设置了默认网络地址的 UDPsocket 也可以调用该接口来发送数据.
 *
 *  @param socketFileDescriptor  socket 描述字
 *  @param void                 数据容器
 */
ssize_t send((int)newSocker, (const void *)buffer, (size_t)bufferLength, int flag);


/**
 *  从 socket 中读取数据, 读取成功之后返回读取的字节数, 否则返回 -1.
 一旦连接建立好之后, 就可以接收数据了, 注意, 嗲用 connect 设置了默认网络地址的 UDPsocket 也可以调用该接口来接收数据.
 */
ssize_t recv((int)newSocker, buffer, (size_t)sizeof(buffer), int flag);


/**
 *  通过 UDPsocket 发送数据到特定的网络地址, 发送成功返回发送的字节数, 否则返回 -1.网络地址发送数据, 所以可以指定特定网络地址, 以向其发送数据.
 由于 UDP 可以向多个
 *
 *  @param socketFileDescriptor     socket 描述字
 *  @param buffer                   存放要发送的数据的容器
 *  @param destinationAddress       目标地址的 IP 地址结构体
 *  @param destinationAddressLength 目标地址结构体的长度
 */
size_t sendto((int)socketFileDescriptor, (const void *)buffer, (size_t)sizeof(buffer), int flag, (const struct sockaddr *)&destinationAddress, (socklen_t)destinationAddressLength);


/**
 *  从 UDPsocket 中读取数据, 并保存发送者的网络地址信息,读取成功返回读取的数据字节数, 否则返回 -1. 
 由于 UDP 可以接收来自多个网络地址的数据, 所以需要提供额外的参数, 以保存该数据发送者的身份.
 */
size_t recvfrom((int)socketFileDescriptor, (const void *)buffer, (size_t)sizeof(buffer), int flag, (struct sockaddr *restrict)&fromAddress, (socklen_t *restrict)&fromAddressLength); 


/**
 *  getsocketname() 可以获得一个与 socket 相关的地址.
 服务器端可以通过它得到相关客户端的地址;
 服务端也可以得到当前已连接成功的 socket 的 ip 和端口.
 
 第二种情况在客户端不进行 bind() 而直接连接服务器时, 而客户端需要知道当前使用哪个 ip 进行通信时比较有用(如多网卡的情况).
 
 对于 TCP 连接情况: 如果不使用 bind() 指定 ip 和端口, 那么调用 connect() 连接成功之后, 使用 getsocketname() 可以正确获得当前正在通信的 socket 的 ip 和端口地址.
 对于 UDP 连接情况: 无论是在调用 sendto() 之后还是在收到服务器返回的信息之后调用, 都无法得到正确的 ip 地址, 使用 getsocketname() 得到的 ip 为0, 端口正确.
 *
 *  @param int socket 描述字
 */
int getsockname((int)socketFileDescriptor, (struct sockaddr *restrict)&address, (socklen_t *restrict)&addressLength);

相关文章

  • 动脑学院架构篇-Java Socket编程基础及深入讲解

    【Socket】Java Socket编程基础及深入讲解 Socket是Java网络编程的基础,了解还是有好处的,...

  • 【tcp】网络分析好文

    socket 编程基础知识https://cizixs.com/2015/03/29/basic-socket-p...

  • Netty

    一、网络编程基础原理 1 网络编程(Socket)概念 首先注意,Socket不是Java中独有的概念,而是一个语...

  • 2019-03-27 归纳socket

    归纳socket socket socket也称套接字,网络编程的基础。一般情况下我不喜欢直接去说socket的函...

  • socket编程基础

    网络层 物理层(实体)、数据链路层、网络层、传输层、应用层。 TCP连接的三次握手 第一次握手:客户端发送syn包...

  • socket编程基础

    一 . 网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行...

  • socket 编程基础

    TCP 服务器的工作流程: 服务器调用 socket() 创建 socket; 服务器调用 bind() 绑定端口...

  • socket编程基础

    字节序 字节序分为大端字节序和小端字节序大端字节序: 是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内...

  • PHP Socket 编程实战总结

    在进入 PHP Socket 编程实战之前,我们先来了解一下 PHP Socket 的一些基础知识。 一、基础部分...

  • 许世伟的Go语言基础 第五章总结

    第5章 网络编程 5.1 socket编程 以往socket编程: 建立socket:使用socket()函数。 ...

网友评论

      本文标题:socket 编程基础

      本文链接:https://www.haomeiwen.com/subject/nsaclttx.html