IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 计算机网络-自顶向下笔记-套接字编程 -> 正文阅读

[系统运维]计算机网络-自顶向下笔记-套接字编程

Socket套接字编程🐣

由于套接字编程是很庞大的,本文作为学习笔记也仅仅实现了较为简单和基础的部分,但是希望对大家有帮助

所有计算机网络学习笔记链接

在这里插入图片描述

套接字在标识通信端点的时候是不同的

  • 对外: 使用IP地址+端口号
  • 对内:使用套接字描述符进行标识

套接字地址结构:

//IP socket address structure
//sockaddr_in: 因特网套接字地址
struct sockaddr_in {
  uint_16_t			 sin_family;			//协议族
  uint_16_t			 sin_port;				//端口
  struct in_addr sin_addr;				//32位的IP地址
  unsigned char  sin_zero[8];			//sizeof (struct sockaddr)
}


//用于:connect, bind, accept
struct sockaddr {
  uint16_t			safamily;
  char 					sa_data[14];
}

在connect, bind, accept函数中要求一个指向与协议相关的套接字地址结构指针,我们通过设置一个通用的sockaddr数据结构指针,然后标明套接字地址的时候进行强制转换成为这个通用的指针(使之能够接受各种类型的套接字地址结构)

socke函数讲解

cocket

创建一个套接字,函数如下

AF_INET表明我们正在使用32位的IP地址

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

int socket(int domain, int type, int protocol)
#成功返回非负描述符号, 出错返回-1
#实例
clientfd = socket(SF_INET, SOCK_STREAM, 0);		//default : 0

bind

下面的bind, listen, accept: 服务器使用这些函数来同客户端建立连接

bind函数告诉内核将addr中的服务器套接字地址和套接字描述符号sockfd联系起来

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr * addr, socklen_t addrlen);
#成功返回0 出错返回 -1

listen

listen函数用与告诉内核:套接字描述符号是被 服务器而不是 客户端所使用的

listen函数将sockfd从一个主动套接字转化为一个监听套接字,这个套接字接收客户端的请求。

backlog就指明了排队连接的数目

#include <sys/socket.h>
int listen(int sockfd, int backlog);

#成功就返回0 否则就返回 -1

accept

服务器通过调用accept函数来等待来自客户端的连接请求

返回的是 非负连接描述符号(已连接描述符),就是创建了一个新的套接字单独的和客户端套接字进行通信连接。原本的 监听描述符继续等待新的客户端的申请,这样就可以同时处理很多的客户端申请了

#include <sys/socket.h>

int accept(int listenfd, struct sockaddr * addr, int * addrlen);

#成功就返回 非负连接描述符号,出错就返回 -1

read & write 函数, 叫法不一样,就是进行二者的交互嘛

#read用于读取数据
ssize_t read (int fd, void * buf, size_t count);

#write 用于写数据, 同样也是阻塞式的
ssize_t write(int fd, const void * buf, size_t count);

客户端通过调用connect函数来建立和套接字地址为addr的服务器之间的连接

connec函数会发生阻塞:直到连接成功或者是发生了错误

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

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

为了使程序在不同的主机之间传输的时候得到正确的解释🦁?,需要进行字节序的转换

uint32_t htonl(uint32_t hostlong);   //32位主机转网络
uint16_t htons(uint16_t hostshort);  //16位主机转网络
uint32_t ntohl(uint32_t netlong);    //32位网络转主机
uint16_t ntohs(uint16_t netshort);   //16位网络转主机

套接字案例

点对点的一个客户端发送信息给服务器端,然后服务器端将内容复制后重新发送的场景

s e r v e r . c server.c server.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>

const int MYPORT = 8887;
const int QUEUE  = 20;
const int BUFFER_SIZE = 20;



/*
(2) struct sockaddr_in(IP专用的地址结构)

structsockaddr_in {

u_char    sin_len;//长度

u_short   sin_family;//协议

u_short    sin_port;//端口

structin_addr   sin_addr;//ip地址

char   sin_zero[8];//数据

};

(3) struct in_addr

structin_addr {undefined

           u_longs_addr;

};
*/
//Server_addr : 指明远程的IP地址和端口号码
int main()
{
    //创建了套接字
    int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    //定义sockaddr_in
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(MYPORT);       //端口的转换函数
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);    //IP地址
    //bind 成功返回0,出错返回 -1
    if (bind(server_sockfd, (struct sockaddr *) & server_sockaddr, sizeof(server_sockaddr)) == -1) {
        perror("bind");
        exit(1);
    }
    printf ("监听:%d端口\n", MYPORT);
    //listen成功的话返回0 , 出错返回 -1 
    if (listen(server_sockfd, QUEUE) == -1) {
        perror("listen");
        exit(1);
    }

    //客户端套接字
    char buffer[BUFFER_SIZE];
    struct sockaddr_in client_addr;     //用来标识客户端的结构体
    socklen_t length = sizeof (client_addr);

    printf("等待客户端连接\n");

    //成功 -> 返回非负
    //失败 -> 返回-1
    int conn = accept(server_sockfd, (struct sockaddr*) & client_addr, & length);
    if (conn < 0) {
        perror("connect");
        exit(1);
    }
    printf("客户端成功连接\n");

    while (1) {
        memset(buffer, 0, sizeof (buffer));
        int len = recv(conn, buffer, sizeof (buffer), 0);
        //客户端发送exit时候进行终止退出
        if (strcmp (buffer, "exit\n") == 0 || len <= 0) {
            break;
        }
        printf("来自客户端的数据:%s\n", buffer);
        send(conn, buffer, len, 0);
        printf("发送给客户端的数据:%s\n", buffer);
    }
    close(conn);
    close(server_sockfd);
    return 0;
}

c l i e n t . c client.c client.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>

#define MYPORT 8887
#define BUFFER_SIZE 1024
char * SERVER_IP = "127.0.0.1";

int main()
{
    //定义sockfd
    int sock_cli = socket(AF_INET, SOCK_STREAM, 0);

    //定义一下sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof (servaddr));

    servaddr.sin_family = AF_INET;      //定义协议族
    servaddr.sin_port = htons(MYPORT);
    servaddr.sin_addr.s_addr = inet_addr(SERVER_IP);        //服务器IP

    printf("连接%s: %d\n", SERVER_IP, MYPORT);
    //连接服务器,成功返回0 错误返回-1
    if (connect(sock_cli, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
        perror("connect\n");
        exit(1);
    }

    printf("服务器连接成功!\n");

    //建立了同服务器端新创建的套接字的连接
    char sendbuf[BUFFER_SIZE];
    char recvbuf[BUFFER_SIZE];

    while (fgets(sendbuf, sizeof (sendbuf), stdin) != NULL ) {
        printf("向服务器发送数据: %s\n", sendbuf);
        send(sock_cli, sendbuf, strlen(sendbuf), 0);
        if (strcmp(sendbuf,"exit\n") == 0) {
            break;      //输入exit就退出了
        }
        recv(sock_cli, recvbuf, sizeof(recvbuf), 0);
        printf("从服务器接收数据:%s\n", recvbuf);

        memset(sendbuf, 0, sizeof (sendbuf));
        memset(recvbuf, 0, sizeof (recvbuf));
    } 
    close(sock_cli);
    return 0;
}

参考资料

https://blog.csdn.net/weixin_44164489/article/details/108606391

https://blog.csdn.net/chengqiuming/article/details/89298442

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-02-06 14:09:05  更:2022-02-06 14:11:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 5:52:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码