1.Socket编程

CMakeLists文件:

cmake_minimum_required(VERSION 3.19)
project(CS)

set(CMAKE_CXX_STANDARD 11)
include_directories(./include)
link_libraries(pthread)
    
add_executable(client client.cpp)
add_executable(server server.cpp)

socket函数:

SYNOPSIS
       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       int socket(int domain, int type, int protocol);
       失败返回-1
ARGUMENTS:
    domain:IP层协议
           AF_LOCAL AF_UNIX AF_INET AF_INET6
    type:传输层协议
           SOCK_STREAM SOCK_DGRAM SOCK_SEQPACKET SOCK_RAW SOCK_RDM SOCK_PACKET
    protocol:可写为0,根据type参数自动决定    

客户端调用connect连接:连接错误返回-1

NAME
       connect - initiate a connection on a socket

SYNOPSIS
       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

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

#include <netinet/in.h>
#include <unistd.h>
#include <cstring>
#include <arpa/inet.h>

char ip[] = "127.0.0.1";
int port = 9999;
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr(ip);
sockaddr.sin_port = htons(port);

if(connect(csockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0){
    perror("connect");
    close(csockfd);
    return 1;
}

发送与接收消息:recv与send函数在相应的缓冲区为空或满时阻塞

NAME
       send, sendto, sendmsg - 从套接字发送消息

概述
       #include <sys/types.h>
       #include <sys/socket.h>

       int send(int s, const void *msg, size_t len, int flags);
       int  sendto(int s, const void *msg, size_t len, int flags, const struct
       sockaddr *to, socklen_t tolen);  //用于UDP通信
       int sendmsg(int s, const struct msghdr *msg, int flags);

       参数 flags 是一个标志字,可以包含下列标志:

       对于支持带外数据的套接字,
       MSG_OOB   将送出   out-of-band   (带外)数据(比如,    SOCK_STREAM
              类型的套接字); 下层协议也必须支持.  带外 数据.

       MSG_DONTROUTE
              在送出分组时不使用网关.只有直接连接在网络上的主机
              才能接收到数据.这个标志通常仅用于诊断和路由程序.
              可路由的协议族才能使用这个标志;包套接字不可以.

       MSG_DONTWAIT
              使用非阻塞式操作;如果操作需要阻塞,将返回   EAGAIN  错误(也可以用
              F_SETFL fcntl(2) 设置 O_NONBLOCK 实现这个功能.)
       
       MSG_DONTWAIT
              使用非阻塞式操作;如果操作需要阻塞,将返回   EAGAIN  错误(也可以用
              F_SETFL fcntl(2) 设置 O_NONBLOCK 实现这个功能.)

       MSG_NOSIGNAL
              当流式套接字的另一端中断连接时不发送   SIGPIPE   信号,但仍然返回
              EPIPE 错误.

       MSG_CONFIRM (仅用于Linux 2.3以上版本)
              通知链路层发生了转发过程:得到了另一端的成功应答.
              如果链路层没有收到通知,它将按照常规探测网络上的相邻
              主机(比如通过免费arp).     只能用于   SOCK_DGRAM   和   SOCK_RAW
              类型的套接字,且仅对IPv4和IPv6有效.详情参见 arp(7)
      
       结构体 msghdr 的定义如下.详情参见 recv(2) 和下文.

              struct msghdr {
                  void         * msg_name;     /*地址选项*/
                  socklen_t    msg_namelen;    /*地址长度*/
                  struct iovec * msg_iov;      /*消息数组*/
                  size_t       msg_iovlen;     /*msg_iov中的元素个数*/
                  void         * msg_control;  /*辅助信息,见下文*/
                  socklen_t    msg_controllen; /*辅助数据缓冲区长度*/
                  int          msg_flags;      /*接收消息标志*/
              };

       ssize_t recv(int sockfd, void *buf, size_t len, int flags);

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

       ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

服务器端绑定并监听:

NAME 名称
       listen - listen for connections on a socket 在一个套接字上倾听连接

SYNOPSIS 概述
       #include <sys/socket.h>

       int listen(int s, int backlog);
       
       backlog参数为一次性可以接收的连接数,最大为128
       
函数执行成功时返回0.错误时返回-1,并置相应错误代码.
if(::bind(ssockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0){
        perror("bind");
        close(ssockfd);
        return 1;
    }
if(listen(ssockfd, 128) < 0){
        perror("listen");
        close(ssockfd);
        return 1;
    }

accept函数接收连接,成功返回用于通信的fd,失败返回-1

while(true){
        int cfd = accept(ssockfd, nullptr, nullptr);
        if(cfd < 0){
            perror("accept");
            close(cfd);
            close(ssockfd);
            return 1;
        }

        char recvBuff[1024] = {0};
        int len = recv(cfd, recvBuff, sizeof(recvBuff), 0);
        if(len < 0){
            perror("recv");
            close(cfd);
            close(ssockfd);
            return 1;
        }
        cout << "recieved from client:" << recvBuff << endl;

        char sendBuff[1024] = "I recieved your message";
        len = send(cfd, sendBuff, sizeof(sendBuff), 0);
        if(len < 0){
            perror("send");
            close(cfd);
            close(ssockfd);
            return 1;
        }

        close(cfd);
    }

字节序:

小端:主机字节序,低位字节存储在低地址位

大端:网络字节序,低位字节存储在高地址位

转换:#include<arpa/inet.h>

短整型从主机字节序转为网络字节序:uint16_t htons(uint16_t hostshort)

整型从主机字节序转为网络字节序:uint32_t htonl(uint32_t hostshort)

反过来:uint16_t ntohs(uint16_t netlong) 转端口

​ uint32_t ntohl(uint32_t netlong) 转ip地址

主机字节序的ip地址转换为网络字节序:

int inet_pton(int af, const char* src, void* dst)

af:AF_INET,AF_INET6

src:要转换的ip字符串

dst:整型变量的地址,用来存储转换的大端的整型数

成功返回1,返回0则ip字符串有问题,返回-1表示af参数不对

反过来

const char* inet_ntop(int af,const char* src,void* dst, socket_t size)

size是dst对应内存的大小

函数调用成功,返回dst的值,调用失败返回空指针

将点分十进制ip转换为大端整型:只能进行IPV4

in_addr_t inet_addr(const char* cp)

反过来char* inet_ntoa(struct in_addr_in)

客户端根据域名/主机名/字符串IP获取大端序IP:

struct hostent* gethostbyname(const char* name);

struct hostent{

char* h_name; //主机名

char** h_aliases; //主机所有的别名

short h_addrtype; //AF_INET、AF_INET6

short h_length; //主机IP地址长度

char** h_addr_list //主机IP地址

}

memcpy(&sockaddr,sin_addr,h->h_addr,h->h_length);

通信时序:

三次握手:

  1. 客户端调用connect函数,发出SYN请求,服务端调用accept函数接收请求
  2. 服务端发送SYN+ACK,客户端connect函数返回
  3. 客户端发送ACK,服务端accept函数返回

数据传输:

write函数发送数据,read函数返回后发送ACK,若返回为0,则表示接收缓冲区为空

四次挥手:

  1. 客户端调用close函数请求关闭连接,发送FIN
  2. 服务端收到后发送ACK
  3. 服务端read返回0时调用close,发送FIN+ACK
  4. 客户端close返回,发送ACK,服务端收到后close返回
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值