const 发布的文章

“const”

Go语言里面提供了net/http包,我们通过http包来搭建一个的Web服务器。

package main
import(
    "fmt"
    "net/http"
    "log"
    "os"
    "os/signal"
    "syscall"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {        
    w.Header().Set("Content-Type", "text/html; charset=utf-8")
    fmt.Fprintf(w,"<hr/>")
    fmt.Fprintf(w, "<h1>Hello https://const.net.cn!</h1>")
}    

func main(){
    fmt.Println("first web server demo.")
    // 创建系统信号接收器
    done := make(chan os.Signal)
    signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
    go func() {
        <-done 
        fmt.Println("Shutdown server")
        os.Exit(1)
    }()
    fs := http.FileServer(http.Dir("e:/")) 
    http.Handle("/static/", http.StripPrefix("/static/", fs))
    http.HandleFunc("/", sayhelloName) 
    err := http.ListenAndServe(":8080", nil) 
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

访问http://127.0.0.1:8080/

效果如下:
2021-06-12_170307.png

访问http://127.0.0.1:8080/static/
效果如下:
2021-06-12_170344.png

1、登录页面html

<!DOCTYPE HTML>
<html class="no-js">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="renderer" content="webkit">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>登录</title>
        <meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" href="/static/css/style.css?v=17.10.30">
  </head>
    <body class="body-100">

<div class="typecho-login-wrap">
    <div class="typecho-login">
        <form action="" method="post" name="login" role="form">
            <p>
                <label for="name" class="sr-only">用户名</label>
                <input type="text" id="name" name="username" value="" placeholder="用户名" class="text-l w-100" autofocus />
            </p>
            <p>
                <label for="password" class="sr-only">密码</label>
                <input type="password" id="password" name="password" class="text-l w-100" placeholder="密码" />
            </p>
            <p class="submit">
                <button type="submit" class="btn btn-l w-100 primary">登录</button>
            </p>
        </form>        
    </div>
</div>
    </body>
</html>

2、处理网站登录以及获取http post数据,验证密码功能

package main

import (
    "fmt"
    "html/template"
    "log"
    "net/http"
    "strings"
    "time"
)

type Item struct {
    Name  string
    Price int
}

func logouthanler(w http.ResponseWriter, r *http.Request) {
    expiredTime := time.Now()
    c1 := &http.Cookie{
        Name:     "username",
        Expires: expiredTime,
        MaxAge:   -1,
        HttpOnly: true,
    }

    http.SetCookie(w, c1)
}

// 登陆页面
func loginhanler(w http.ResponseWriter, r *http.Request) {

    // 如果是post请求,注意先后顺序
    if r.Method == http.MethodPost {
        // 解析表单 并且校验
        r.ParseForm()
        for k, v := range r.Form {
            fmt.Println("key:", k)
            fmt.Println("val:", strings.Join(v, "-"))
        }
        userName := r.FormValue("username")
        pwd := r.FormValue("password")
        fmt.Println("userName:", userName)
        fmt.Println("pwd:", pwd)

        // 如果输入正确,则发送cookie 并给出反馈
        if userName == "const" && pwd == "const" {

            c1 := &http.Cookie{
                Name:     "username",
                Value:    userName,
                MaxAge:   0,
                HttpOnly: true,
            }

            http.SetCookie(w, c1)

            //fmt.Fprint(w, "登陆成功")
            http.Redirect(w, r, "/manage", http.StatusFound)
        } else {
            fmt.Fprint(w, "登陆失败")
        }

        // 显示登录页面
    } else {
        // 解析模板
        t, err := template.ParseFiles("index.html")
        if err != nil {
            log.Fatal(err)
        }
           t.Execute(w, "")
    }    
}   
func manageHandler(w http.ResponseWriter, r *http.Request) {
    username, err := r.Cookie("username")
    if err != nil || username.Value == "" {
        http.Redirect(w, r, "/", http.StatusFound)
    }

    fmt.Println("enter manage1")
    t, err := template.ParseFiles("manage.html")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("enter manage2")
    t.Execute(w, username.Value)
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", loginhanler)
    mux.HandleFunc("/login", loginhanler)
    mux.HandleFunc("/manage", manageHandler)
    mux.HandleFunc("/logout", logouthanler)
    fs := http.FileServer(http.Dir("."))
    mux.Handle("/static/", http.StripPrefix("/static/", fs))

    server := &http.Server{
        Addr:    ":8080",
        Handler: mux,
    }

    err := server.ListenAndServe()
    if err != nil {
        log.Fatal(err)
    }

}

3、登录效果
2021-06-14_201101.png

2021-06-14_201143.png

sendto(),把UDP数据报发给指定地址和端口。
函数原型
int sendto (int s, const void buf, int len, unsigned int flags, const struct sockaddr to, int tolen);
参数说明
s: socket描述符。
buf: UDP数据报缓存地址。
len: UDP数据报长度。
flags: 该参数一般为0。
to: sendto()函数参数,struct sockaddr_in类型,指明UDP数据发往哪里报。
tolen: 对方地址长度,一般为:sizeof(struct sockaddr_in)。
函数返回值
对于sendto()函数,成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。

发送udp数据示例

int udp_send(string ip, int port, string data)
{
    int sockfd;
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        printf("socket error\n");
        return -1;
    }
    struct sockaddr_in addrto;
    bzero(&addrto, sizeof(struct sockaddr_in));
    addrto.sin_family = AF_INET;
    addrto.sin_addr.s_addr = htonl(INADDR_ANY);
    addrto.sin_port = htons(9999);
    //设置广播
    int yes = 1;
    setsockopt(m_nsockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));    
    if(bind(m_nsockfd, (struct sockaddr *) & (addrto), sizeof(struct sockaddr_in)) == -1)
    {
        printf("udp_listen bind error...\n");
        return -1;
    }  
    int addrlen = sizeof(sockaddr_in);
    struct sockaddr_in addr;
    bzero(&addr, sizeof(struct sockaddr_in));    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    return sendto(m_nsockfd, data.data(), data.length(), 0, (struct sockaddr *)&addr, addrlen);
}

php 实现udp发送数据,主要使用 socket_sendto就可以了。

  $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
  //PHP UDP socket_ recv() timeout
  socket_set_option($socket,SOL_SOCKET,SO_RCVTIMEO,array("sec"=>2,"usec"=>0));

  //Set socket options.
  socket_set_nonblock($socket);
  socket_set_option($socket, SOL_SOCKET, SO_BROADCAST, 1);
  socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
  if (defined('SO_REUSEPORT'))
      socket_set_option($socket, SOL_SOCKET, SO_REUSEPORT, 1);

  //Bind to any address & rand port 
  socket_bind($socket, '0.0.0.0', 9999)
  
  $senddata = "hello";
  socket_sendto($socket,$sendcmd, strlen($senddata), 0, "127.0.0.1", 54321);

php 设置socket 非阻塞

socket_set_nonblock($socket);

php 设置udp 广播

socket_set_option($socket, SOL_SOCKET, SO_BROADCAST, 1);

php 设置 udp 地址端口重用

socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);

php 设置udp_recv接收超时

  socket_set_option($socket,SOL_SOCKET,SO_RCVTIMEO,array("sec"=>2,"usec"=>0));

php 字符串转大写

uppercase

php 判断http post

 function is_post()
{
    return isset($_SERVER['REQUEST_METHOD']) && strtoupper($_SERVER['REQUEST_METHOD'])=='POST';    
}

php 取随机数

echo(rand();
echo(rand();
echo(rand(10,100))

php socket 官方链接地址
https://www.php.net/manual/en/book.sockets.php

php explode 示例

$arr = explode(":", $buf);

php trim 示例 

$str = "Hello Const!";
echo $str . "<br>";
echo trim($str,"Const!");

<?php
$hex = hex2bin("6578616d706c65206865782064617461");
var_dump($hex);
?>

输出

string(16) "example hex data"

bin2hex() 函数把 ASCII 字符的字符串转换为十六进制值。

<?php

$str = bin2hex("Shanghai");
echo($str);
?>

输出

5368616e67686169