Socket网络编程基础知识

网络基础知识

网络层级结构

1、物理层

2、数据链路层 链路层/以太网帧协议、ARP

3、网络层 网络层 /IP /ICMP/IGMP

4、传输层 传输层TCP/UDP

5、会话层 应用层/http/https/ft

6、表示层

7、应用层

IP地址:在网络环境中唯一标识一台主机,是一个点分十进制字符串

端口号:在主机中唯一标识一个进程

IP+Port:在网络环境中唯一标识一个进程

1、socket 是成对出现

2、socket 一定需要绑定IP + 端口

3、Linux的socket是一个文件描述符指向两个缓冲区,一个是读,一个是写

网络字节序

  • 小端:高位存高地址,地位存低地址 (计算机存储)

  • 大端:高位存低地址,地位存高地址 (网络字节序)

    • 函数

      • htonl() -> 本地->网络 (ip)
      • htons() -> 本地-> 网络 (端口)
      • ntohl() -> 网络-> 本地 (ip)
      • ntohs() -> 网络 -> 本地 (port)

      IP地址转换及其相关的socket函数

      int inet_pton(int af, const char *src, void *dst); 本地字节序(string ip ) -> 网络字节序
      params:
      	af: AF_INET, AF_INET6
          src: 传入的IP地址,(点分十进制)
          dts: 传出,网络字节序
          return: 0 , 说明src 指向的不是一个有效的IP地址, 异常
                  1, 成功
                  -1, 失败
           
      const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
      	af: AF_INET, AF_INET6
          src: 网络字节序IP地址
          dst: 本地字节序(string ip)
          return:
      		success: dst
      		failed:NULL
      	
      
                  
      sockaddr 地址结构:
          struct sockaddr_in addr;
      	addr.sin_family = AF_INET;
      	addr.sin_port = htos(8882);
      	int dst;
      	inet_pton(AF_INET, "22.33.22.21", (void*)&dst);
          //addr.sin_addr.s_addr = dst;
      	addr.sin_addr.s_addr = htol(INADDR_ANY); 
      	/*两种写法一样的,但是第二种更加简单*/  
      	/*man 3 ip*/
          bind(fd, (struct sockaddr*)&addr, len);
      	
      	listen() 设置监听上限并发
          accept() 阻塞监听客户端连接
              
              
           #include <sys/socket.h>
           int socket(int domain, int type, int protocol);
      	 domain: AF_INET/AF_INET6/AF_UNIX
      	 type: SOCKET_STREAM/SOCKET_DGRAM
      	 protocol:0
      	 return:
      		成功:返回fd
              失败:返回NULL
      
      
           int bind(int sockfd, const struct sockaddr *addr,
                      socklen_t addrlen);
      
      		 sockfd: socket 返回的函数值
      		 addr:
      				struct sockaddr_in addr;
      				addr.sin_family = AF_INET;
      				addr.sin_port = htons(882);
      				addr.sin_addr.s_addr = htonl(INADDR_ANY);
      				(structr sockaddr *)&addr;
      		 len:   sizeof(addr) 地址结构的大小
               return:
      			成功:0
                  失败:-1
                      
                      
              // listen
              int listen(int sockfd, int backlog); 设置同时与服务器建立连接的上限数。(同时进行3次握手的客户端数量)
               sockfd: socket 返回值
               backlog:上限数值,最大值(128return:
      			成功:0
                  失败:-1
                      
                      
              //accept
              // comment:阻塞等待客户端建立连接,成功的话,返回一个与客户端成功连接的socket文件描述符
      		int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);  
      		sockfd:socket 返回值
      		addr:传出参数,成功与服务器建立连接的哪个客户端的地址结构
              addrlen:传入传出参数,入:addr的大小值,出是客户端的实际大小
                  socketlen_t client_addr_len = sizeof(addr);
      		return:
      			成功:能与server通信的客户端的socket文件描述符
                  失败:-1, errno
                      
                      
              // connect
              // comment:
                      //使用现有的socket与server建立连接
             int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
      		sockfd:socket 返回值
      		addr:传入服务器的地址结构
              addrlen:传入传出参数,sizeof(addr)
              
              return:
      			成功:0
                  失败:-1
               
               
              
      

简单的服务端开发流程

有数据
没数据
开始
socket fd建立
bind 绑定
listen 设置监听数量
accept 进入阻塞环节
循环等待监听
read读
write写
close 结束
数据处理

客户端实现流程

开始
socket 建立
connect 建立连接
write 写数据给server
read 等待读取数据
close

代码示例:

/*
 * @Description: TCP Server 端代码
 * @Version: V0.01
 * @Author: 
 * @Date: 
 * @LastEditors: 
 * @LastEditTime: 
 */
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <iostream>
#include <arpa/inet.h>

void print_error(const char *str) {
    perror(str);
    exit(1);
}



int main(int argc, char const *argv[])
{
    

    char msg[BUFSIZ];

    int server_fd = socket(AF_INET, SOCK_STREAM, 0); 
    if (server_fd == -1) {
        print_error("socket build error");
    }

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(8888);

    int err = bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));

    listen(server_fd, 128); // 设置并发数为128个连接

    
    socklen_t cli_len;
    struct sockaddr_in client_addr;

    
    std::cout << "Server running ..." << std::endl;

    int cli_fd = accept(server_fd, (struct sockaddr *)&client_addr, &cli_len);
    if(cli_fd == -1) {
        print_error("get client accept error");
    }

    char client_ip[128];

    std::cout  << "Client ip:" << std::string(inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, client_ip, sizeof(client_ip))) \
    << " Client port:" << ntohs(client_addr.sin_port) << std::endl;

    
    int msg_len = read(cli_fd, msg, sizeof(msg));
    for (int i = 0; i < cli_len; i++) {
        msg[i] = toupper(msg[i]);
    }
    write(cli_fd, msg, msg_len);
    close(cli_fd);
    close(server_fd);

    return 0;
}
/*
 * @Description: TCP socket 客户端
 * @Version: V0.01
 * @Author: 
 * @Date: 
 * @LastEditors: 
 * @LastEditTime: 
 */
#include <sys/socket.h>
#include <sys/types.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
// #include <ctype.h>
#include <iostream>
#include <arpa/inet.h>

void print_error(const char * str) {
    perror(str);
    exit(1);
}

int main(int argc, char const *argv[])
{
    
    char msg_buf[] = "Hello world!";

    int client_fd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in svr_addr;
    
    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(8888);
    // inet_
    svr_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    int err = connect(client_fd, (struct sockaddr*)&svr_addr, sizeof(svr_addr));

    if (err!= 0) {
        print_error("connect error");
    }

    write(STDOUT_FILENO, msg_buf, strlen(msg_buf));
    write(client_fd, msg_buf, strlen(msg_buf));
    read(client_fd, msg_buf, strlen(msg_buf));
    std::cout << std::endl;
    write(STDOUT_FILENO, msg_buf, strlen(msg_buf));

    close(client_fd);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值