20201317 LYX 第12周学习总结

第12周

知识总结

  1. 论述TCP/IP协议及其应用,具体包括TCP/IP栈、IP地址、主机名、DNS、IP数据包和路由器;
  2. 介绍TCP/IP网络中的UDP和TCP协议端口号数据流;
  3. 阐述服务器—客户机计算模型套接字编程接口;
  4. 介绍Web和CGI编程,解释HTTP编程模型、Web页面和Web浏览器;
  5. 展示如何配置Linux HTTPD服务器来支持用户Web页面、PHP和CGI编程;
  6. 阐释客户机和服务器端动态Web页面。

一、TCP 协议的作用

互联网由一整套协议构成。TCP 只是其中的一层,有着自己的分工。

这里写图片描述

最底层的以太网协议(Ethernet)规定了电子信号如何组成数据包(packet),解决了子网内部的点对点通信。

这里写图片描述

但是,以太网协议不能解决多个局域网如何互通,这由 IP 协议解决。

这里写图片描述这里写图片描述

Socket套接字

套接字是网络编程中的一种通信机制,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

前面介绍过,本地的进程间通信(IPC)有很多种方式,常见的总结以下几点:

1、管道(包括无名管道和命名管道);
2、消息队列;
3、信号量;
4、共享存储。
5、……( Socket和Streams支持不同主机上的两个进程IPC)。
这里写图片描述

这里写图片描述

java实践(原创 SM2加密 一次一密)

ChatClient

package TCP3;

import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.util.encoders.Hex;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Scanner;

import static TCP1.SM2Utils.*;

/**
 * 注意用到的输入输出流DataInputStream和DataOutputStream,成对出现,最好用字节流
 * 20201317 Yongxin Lu
 * 2022/11/3
 */
// 客户端类
public class ChatClient {//创建公共类
    private String host = "localhost";// 默认连接到本机
    private int port = 8189;// 默认连接到端口8189

    public ChatClient() {

    }

    // 连接到指定的主机和端口
    public ChatClient(String host, int port) {//构造方法
        this.host = host;//将构造方法的参数host传递给类变量host
        this.port = port;//将构造方法的参数port传递给类变量port
    }

    public void chat() {//chat方法

        //socket链接
        try {
            // 连接到服务器
            Socket socket = new Socket(host, port);//创建Socket类对象

            try {

                DataInputStream in = new DataInputStream(socket
                        .getInputStream());// 读取服务器端传过来信息的DataInputStream

                DataOutputStream out = new DataOutputStream(socket
                        .getOutputStream());// 向服务器端发送信息的DataOutputStream


                Scanner scanner = new Scanner(System.in);// 装饰标准输入流,用于从控制台输入

                while (true) {


                    //SM2的连接准备---实现密钥更迭
                    String publicKeyHex = null;
                    String privateKeyHex = null;
                    KeyPair keyPair = createECKeyPair();
                    PublicKey publicKey = keyPair.getPublic();
                    if (publicKey instanceof BCECPublicKey) {
                        //获取65字节非压缩缩的十六进制公钥串(0x04)
                        publicKeyHex = Hex.toHexString(((BCECPublicKey) publicKey).getQ().getEncoded(false));
                        //System.out.println("---->SM2公钥:" + publicKeyHex);
                    }
                    PrivateKey privateKey = keyPair.getPrivate();
                    if (privateKey instanceof BCECPrivateKey) {
                        //获取32字节十六进制私钥串
                        privateKeyHex = ((BCECPrivateKey) privateKey).getD().toString(16);
                        //System.out.println("---->SM2私钥:" + privateKeyHex);
                    }


                    //生成pubkeyc公钥,并且传向服务器
                    if(publicKeyHex!=null)out.writeUTF(publicKeyHex);
                    System.out.println("send pubkeyc:" + publicKeyHex);//输出键盘输出内容提示 ,也就是客户端向服务器端发送的消息

                    //从服务器接收pubkeys公钥
                    String pubkeys=in.readUTF();
                    System.out.println("pubkeys:"+pubkeys);

                    //发送数据
                    String send = scanner.nextLine();//读取控制台输入的内容
                    // 把从控制台得到的信息传送给服务器
                    String send2="Client:"+send;
                    String encryptData = encrypt(pubkeys, send2);
                    out.writeUTF(encryptData);//将客户端的信息传递给服务器

                    //读取服务器信息,利用私钥解密
                    String accpet = in.readUTF();// 读取来自服务器的信息
                    System.out.println(accpet);
                    String data = decrypt(privateKeyHex, accpet);
                    System.out.println(data);//输出来自服务器的信息


                }

            } finally {
                socket.close();//关闭Socket监听
            }
        } catch (IOException e) {//捕获异常
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {//主程序方法
        new ChatClient().chat();//调用chat方法
    }
}

ChatServer

package TCP3;

import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.util.encoders.Hex;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Scanner;

import static TCP1.SM2Utils.*;

/**
 * 模拟qq聊天功能: 实现客户端与服务器(一对一)的聊天功能,客户端首先发起聊天,输入的内容在服务器端和客户端显示,
 * 然后服务器端也可以输入信息,同样信息也在客户端和服务器端显示
 */

// 服务器类
public class ChatServer {//ChatServer类
    private int port = 8189;// 默认服务器端口

    public ChatServer() {

    }

    // 创建指定端口的服务器
    public ChatServer(int port) {//构造方法
        this.port = port;//将方法参数赋值给类参数
    }

    // 提供服务
    public void service() {//创建service方法



        try {// 建立服务器连接
            ServerSocket server = new ServerSocket(port);//创建  ServerSocket类
            Socket socket = server.accept();// 等待客户连接
            try {
                DataInputStream in = new DataInputStream(socket
                        .getInputStream());// 读取客户端传过来信息的DataInputStream
                DataOutputStream out = new DataOutputStream(socket
                        .getOutputStream());// 向客户端发送信息的DataOutputStream
                Scanner scanner = new Scanner(System.in);//从键盘接受数据
                while (true) {


                    //SM2的连接准备-->实现密钥更迭
                    String publicKeyHex = null;
                    String privateKeyHex = null;
                    KeyPair keyPair = createECKeyPair();
                    PublicKey publicKey = keyPair.getPublic();
                    if (publicKey instanceof BCECPublicKey) {
                        //获取65字节非压缩缩的十六进制公钥串(0x04)
                        publicKeyHex = Hex.toHexString(((BCECPublicKey) publicKey).getQ().getEncoded(false));
                        //System.out.println("---->SM2公钥:" + publicKeyHex);
                    }
                    PrivateKey privateKey = keyPair.getPrivate();
                    if (privateKey instanceof BCECPrivateKey) {
                        //获取32字节十六进制私钥串
                        privateKeyHex = ((BCECPrivateKey) privateKey).getD().toString(16);
                        //System.out.println("---->SM2私钥:" + privateKeyHex);
                    }


                    //收公钥c
                    String pubkeyc = in.readUTF();// 读取来自客户端的信息
                    System.out.println("pubkeyc:"+pubkeyc);//输出来自客户端的信息

                    //发公钥s
                    if(publicKeyHex!=null)out.writeUTF(publicKeyHex);
                    System.out.println("Send pubkeys:"+publicKeyHex);


                    //读取服务器信息,利用私钥解密
                    String accpet = in.readUTF();// 读取来自服务器的信息
                    System.out.println(accpet);
                    String data = decrypt(privateKeyHex, accpet);
                    System.out.println(data);//输出来自服务器的信息

                    //接收命令行的信息
                    String send = scanner.nextLine();//nextLine方式接受字符串
                    System.out.println("Server:" + send);//输出提示信息

                    //利用公钥加密
                    //System.out.println(send+" len: "+send.length());
                    String send2="Server:"+send;
                    String encryptData = encrypt(pubkeyc, send2);
                    System.out.println("encryptData:"+encryptData);

                    //发送加密后的信息
                    out.writeUTF(encryptData);//把服务器端的输入发给客户端

                    //接收Client信息
                    //String accpet = in.readUTF();// 读取来自客户端的信息
                    //System.out.println("Client:"+accpet);
                }
            } finally {// 建立连接失败的话不会执行socket.close();
                socket.close();//关闭连接
                server.close();//关闭
            }
        } catch (IOException e) {//捕获异常
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {//主程序方法
        new ChatServer().service();//调用 service方法
    }
}

image-20221113000304777

image-20221113000329376

C

Client.c

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

#define SERVER_PORT 9999
#define BUFF_LEN 512
#define SERVER_IP "127.0.0.1"


void udp_msg_sender(int fd, struct sockaddr* dst)
{

    socklen_t len;
    struct sockaddr_in src;
    while(1)
    {
        char buf[BUFF_LEN] = "TEST UDP MSG!\n";
        len = sizeof(*dst);
        printf("client:%s\n",buf);  //打印自己发送的信息
        sendto(fd, buf, BUFF_LEN, 0, dst, len);
        memset(buf, 0, BUFF_LEN);
        recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&src, &len);  //接收来自server的信息
        printf("server:%s\n",buf);
        sleep(1);  //一秒发送一次消息
    }
}

/*
    client:
            socket-->sendto-->revcfrom-->close
*/

int main(int argc, char* argv[])
{
    int client_fd;
    struct sockaddr_in ser_addr;
    
client_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(client_fd < 0)
    {
        printf("create socket fail!\n");
        return -1;
    }

    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    //ser_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //注意网络序转换
    ser_addr.sin_port = htons(SERVER_PORT);  //注意网络序转换

    udp_msg_sender(client_fd, (struct sockaddr*)&ser_addr);

    close(client_fd);

    return 0;
}

Server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

#define SERVER_PORT 9999
#define BUFF_LEN 1024

void handle_udp_msg(int fd)
{
    char buf[BUFF_LEN];  //接收缓冲区,1024字节
    socklen_t len;
    int count;
    struct sockaddr_in clent_addr;  //clent_addr用于记录发送方的地址信息
    while(1)
    {
        memset(buf, 0, BUFF_LEN);
        len = sizeof(clent_addr);
        count = recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&clent_addr, &len);  //recvfrom是拥塞函数,没有数据就一直拥塞
        if(count == -1)
        {
            printf("recieve data fail!\n");
            return;
        }
        printf("client:%s\n",buf);  //打印client发过来的信息
        memset(buf, 0, BUFF_LEN);
        sprintf(buf, "I have recieved %d bytes data!\n", count);  //回复client
        printf("server:%s\n",buf);  //打印自己发送的信息给
        sendto(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&clent_addr, len);  //发送信息给client,注意使用了clent_addr结构体指针

    }
}


/*
    server:
            socket-->bind-->recvfrom-->sendto-->close
*/

int main(int argc, char* argv[])
{
    int server_fd, ret;
    struct sockaddr_in ser_addr;

    server_fd = socket(AF_INET, SOCK_DGRAM, 0); //AF_INET:IPV4;SOCK_DGRAM:UDP
    if(server_fd < 0)
    {
        printf("create socket fail!\n");
        return -1;
    }

    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址
    ser_addr.sin_port = htons(SERVER_PORT);  //端口号,需要网络序转换

    ret = bind(server_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
    if(ret < 0)
    {
        printf("socket bind fail!\n");
        return -1;
    }

    handle_udp_msg(server_fd);   //处理接收到的数据

    close(server_fd);
    return 0;
}

image-20221113001559666

image-20221113001622329

posted @ 2022-11-13 00:17  B1smarck  阅读(14)  评论(0编辑  收藏  举报