计算机网络——15套接字编程

news/2024/7/5 6:35:33

套接字编程

Socket编程

Socket编程:应用进程使用传输层提供的服务才能够交换报文,实现应用协议,实现应用
TCP/IP:应用进程使用Socket API访问传输服务
地点:界面上的SAP
方式:Socket API

目标:学习如何构建能借助sockets进行通信的C/S应用程序
socke:分布式应用进程之间的门,传输层协议提供的端到端服务接口

在这里插入图片描述

2种传输层服务的socket类型

  • TCP:可靠的、字节流的服务
  • UDP:不可靠(数据UDP数据报)服务

TCP套接字编程

套接字:应用进程与端到端传输协议(TCP或UDP)之间的门户
TCP服务:从一个进程向另一个进程可靠的传输字节流

服务器首先运行,等待连接建立
服务器进程必须先处于运行状态

  • 创建欢迎socket
  • 和本地端口捆绑
  • 在欢迎socket上阻塞式等待接受用户的连接

客户端主动和服务器建立连接
创建客户端本地套接字(隐式捆绑到本地port)

  • 指定服务器进程的IP地址和端口号,与服务器进程连接

当与客户端连接请求到来时

  • 服务器接受来自客户端的请求,接触阻塞式等待,返回一个新的socket(与欢迎socket不一样),与客户端通信
    • 允许服务器与多个客户端通信
    • 使用的IP和源端口来区分不同的客户端

连接API调用有效时,客户端P与服务器之间建立了TCP连接

从应用程序的角度
TCP在客户端和服务器进程之间提供了可靠的、字节流(管道)服务

C/S模式的应用样例

  • 客户端从标准输入装置读取一行字符,发送给服务器
  • 服务器从socket读取字符
  • 服务器将字符串装换成大写,然后返回给客户端
  • 客户端从socket种读取一行字符,然后打印出来

实际上,这里描述了C-S之间交互的动作次序

数据结构sockaddr_in

IP地址和port捆绑关系的数据结构(标示进程的端节点)

struct socketaddr_in{
    short sin_family;   //AF_INET
    u_short sin_port;   //port
    struct in_addr sin_addr;    //IP address unsigned long
    char sin_zero[8];   //align
};
属性说明
sin_family地址簇,这个结构体不仅仅用于IP的通信,还可以用于其他的通信,这里设置为常量AF_INET,表明是TCP/IP的协议簇
sin_port端口号
sin_addrip地址
sin_zero起对其作用,因为ipx的地址长度比ip的长度,其他地址也是

数据结构hostent

域名和IP地址的数据结构

struct hostent { 
    char *h_name;	//域名
    char **h_aliases;	//别名
    int h_addrtype;	
    int h_length; //地址长度
    char **h_addr_list;	//IP地址
    #define h_addr h_addr_list[0];
}; 
属性类型说明
h_name字符串主机域名
h_aliases字符串数组主机的一系列别名
h_addrtype
h_length数字地址长度
h_addr_list字符串数组ip地址,可以将其复制到sockaddr_in的ip中

作为调用域名解析函数时的参数 返回后,将IP地址拷贝到 sockaddr_in的IP地址部分

C/S socket交互:TCP

在这里插入图片描述

例子:C客户端(TCP)

// client.c
void main(int argc, char *argv[]) {
    // sad表示 server addr
    struct sockaddr_in sad; /* structure to hold an IP address of server */
    int clientSocket; /* socket descriptor */
    struct hostent *ptrh; /* pointer to a host table entry */
    char Sentence[128];
    char modifiedSentence[128];
    //	argv[0]是程序的名字
    host = argv[1]; // argv[1] 表示服务器的域名
    port = atoi(argv[2]); // argv[2]表示服务端的端口
    clientSocket = socket(PF_INET, SOCK_STREAM, 0);
    // 这里底层自动使用了bind

    // sad先清0
    memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
    sad.sin_family = AF_INET; /* set family to Internet */
    // port先转换成短整形,然后设置成网络次序
    sad.sin_port = htons((u_short)port);
    ptrh = gethostbyname(host);
    /* Convert host name to IP address */
    //将IP地址拷贝到sad.sin_addr
    memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
    connect(clientSocket, (struct sockaddr *)&sad, sizeof(sad));

    gets(Sentence); // get input stream from client
    n=write(clientSocket, Sentence, strlen(Sentence)+1); // send line to server
    n=read(clientSocket, modifiedSentence, sizeof(modifiedSentence)); // read line from server
    printf("FROM SERVER: %s\n",modifiedSentence);
    close(clientSocket);  // close the connection
}

例子:C服务器(TCP)

// server.c
void main(int argc, char *argv[]) {
    // 只有一个参数,就是服务端的端口号
    struct sockaddr_in sad; /* structure to hold an IP address of server*/
    struct sockaddr_in cad; /*client */
    int welcomeSocket, connectionSocket; /* socket descriptor */
    struct hostent *ptrh; /* pointer to a host table entry */
    char clientSentence[128];
    char capitalizedSentence[128];
    // port
    port = atoi(argv[1]);
    welcomeSocket = socket(PF_INET, SOCK_STREAM, 0);
    memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
    sad.sin_family = AF_INET; /* set family to Internet */
    sad.sin_addr.s_addr = INADDR_ANY; /* set the local IP address */
    sad.sin_port = htons((u_short)port);/* set the port number */
    // 此处赋值,在表中进行赋值
    bind(welcomeSocket, (struct sockaddr *)&sad, sizeof(sad));
    
    // specify the maximum number of clients that can be queued
    listen(welcomeSocket, 10)
        while(1) {
            connectionSocket=accept(welcomeSocket, (struct sockaddr *)&cad, &alen);
            n=read(connectionSocket, clientSentence, sizeof(clientSentence));
            // capitalize Sentence and store the result in capitalizedSentence
            n=write(connectionSocket, capitalizedSentence, strlen(capitalizedSentence)+1);
            close(connectionSocket);
        }
}

UDP Socket编程

UDP在客户端和服务器之间没有连接

  • 没有握手
  • 发送端在每一个报文中明确地指明目标的IP地址和端口号
  • 服务器必须从收到的分组中提取出发送端的IP地址和端口号

传送的数据可能乱序,也可能丢失

进程视角看UDP服务
UDP为客户端和服务器提供不可靠的字节组的传送服务

C/S交互:UDP

在这里插入图片描述

例子:C客户端

/* client.c */
void main(int argc, char *argv[])
{
    struct sockaddr_in sad; /* structure to hold an IP address */
    int clientSocket; /* socket descriptor */
    struct hostent *ptrh; /* pointer to a host table entry */
    char Sentence[128];
    char modifiedSentence[128];
    host = argv[1]; port = atoi(argv[2]);
    clientSocket = socket(PF_INET, SOCK_DGRAM, 0);
    /* determine the server's address */
    memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
    sad.sin_family = AF_INET; /* set family to Internet */
    sad.sin_port = htons((u_short)port);
    ptrh = gethostbyname(host);
    /* Convert host name to IP address */
    memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
    gets(Sentence);
    addr_len =sizeof(struct sockaddr);
    n=sendto(clientSocket, Sentence, strlen(Sentence)+1, (struct sockaddr *) &sad, addr_len);
    n=recvfrom(clientSocket, modifiedSentence, sizeof(modifiedSentence),(struct sockaddr *) &sad, &addr_len);
    printf("FROM SERVER: %s\n",modifiedSentence);
    close(clientSocket);
}

例子:C服务器

/* server.c */
void main(int argc, char *argv[])
{
    struct sockaddr_in sad; /* structure to hold an IP address */
    struct sockaddr_in cad;
    int serverSocket; /* socket descriptor */
    struct hostent *ptrh; /* pointer to a host table entry */
    char clientSentence[128];
    char capitalizedSentence[128];
    port = atoi(argv[1]);
    serverSocket = socket(PF_INET, SOCK_DGRAM, 0);
    memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
    sad.sin_family = AF_INET; /* set family to Internet */
    sad.sin_addr.s_addr = INADDR_ANY; /* set the local IP address */
    sad.sin_port = htons((u_short)port);/* set the port number */
    bind(serverSocket, (struct sockaddr *)&sad, sizeof(sad));
    while(1) {
        n=recvfrom(serverSocket, clientSentence, sizeof(clientSentence), 0
                   (struct sockaddr *) &cad, &addr_len );
        /* capitalize Sentence and store the result in capitalizedSentence*/
        n=sendto(serverSocket , capitalizedSentence, strlen(capitalizedSentence)+1,
                 (struct sockaddr *) &cad, &addr_len);
    }
}


http://lihuaxi.xjx100.cn/news/2032200.html

相关文章

System

System System代表程序所在的系统,也是一个工具类 System类提供的常见方法 方法名说明public static void exit(int status)终止当前运行的Java虚拟机public static long currenTimeMillis()返回当前系统的时间毫秒值形式 案例演示 exit() public clas…

CSS的伪类选择器:nth-child()的用法示例

CSS的伪类选择器:nth-child()的用法示例 n可以- , 右边数字只能 第一到第六的td : td:nth-child(n1):nth-child(-n6) td:nth-child(n1):nth-child(-n6)第二到第八的a : a:nth-child(n2):nth-child(-n8) a:nth-child(n2):nth-child(-n8)1等效0n1 , 7等效0n7 , 没有负数,不能…

解决STM32MP157开发板密码登录问题

开发板密码登录问题是很多人遇到的问题,网上有很多帖子,我也参考过,不太适用,很复杂,甚至会被误导,我差点连ubuntu虚拟机都无法登录了。有的密码匹配,有的取消不了密码。 1、密码配置&#xff…

Day-02-01

内容管理模块项目开发 Swagger的使用 1. 导入依赖 <!-- Spring Boot 集成 swagger --> <dependency><groupId>com.spring4all</groupId><artifactId>swagger-spring-boot-starter</artifactId> </dependency> 2. 配置信息 # 在app…

Ubuntu 20.04 安装RVM

RVM是管理Ruby版本的工具,使用RVM可以在单机上方便地管理多个Ruby版本。 下载安装脚本 首先使下载安装脚本 wget https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer 如果出现了 Connection refused 的情况, 可以考虑执行以下命令修改dns,再执…

第三百四十九回

文章目录 1. 概念介绍2. 原理与方法2.1 知识对比2.2 使用方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"加密包crypto"相关的内容&#xff0c;本章回中将介绍characters包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 在项目中会遇到获取字…

突破编程_C++_面试(基本数据类型)

面试题1&#xff1a;在32位和64位系统上&#xff0c;int、short、long、long long 和 char 类型通常分别占用多少字节 在 32 位和 64 位系统上&#xff0c;int、short、long、long long 和 char 类型的大小可能会有所不同&#xff0c;这取决于编译器和操作系统。但按照常见的约…

Rocky Linux 下载安装

一、VMware Workstation下载安装 1、安装教程 VMware Workstation下载安装&#xff08;含密钥&#xff09; 二、VMware Workstation 创建虚拟机 1、创建教程 VMware Workstation 创建虚拟机 三、Rocky Linux 下载 1、下载官网 RockyLinux.org 2、选择X86架构_64位系统_DVD镜…