首页 > 编程语言 >第十一章:网络编程

第十一章:网络编程

时间:2023-04-03 21:02:17浏览次数:32  
标签:err 第十一章 fmt 编程 网络 Println buf conn 客户端

在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。

因此可以用Socket来描述网络连接的一对一关系。

常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。

1 TCP的C/S架构

1.1 单服务版本

服务端代码:

package main  
  
import (  
   "fmt"  
   "net")  
  
  
func main() {  
   // 创建监控  
   listener, err := net.Listen("tcp", "localhost:8000")  
   if err != nil {  
      fmt.Println("listen err:", err)  
      return  
   }  
  
   defer listener.Close()  // 主协程结束时,关闭listener  
  
   fmt.Println("服务器等待客户端建立连接...")  
  
   // 等待客户端连接请求  
   conn, err := listener.Accept()  
  
   if err != nil {  
      fmt.Println("accpet err:", err)  
      return  
   }  
   defer conn.Close()  // 使用结束,断开与客户端链接  
   fmt.Println("客户端与服务器连接建立成功...")  
  
   // 接收客户端数据  
   buf := make([]byte, 1024)  // 创建1024大小的缓冲区,用于read  
  
   n, err := conn.Read(buf)  // 读取到n个大小的数据  
  
   if err != nil {  
      fmt.Println("read err:", err)  
      return  
   }  
  
   fmt.Println("服务器读到:", string(buf[:n])) // 读多少,打印多少  
}

如图,在整个通信过程中,服务器端有两个socket参与进来,但用于通信的只有 conn 这个socket。它是由 listener创建的。隶属于服务器端。

客户端代码:

package main  
  
import (  
   "fmt"  
   "net")  
  
func main() {  
   // 主动发送连接请求  
   conn, err := net.Dial("tcp", "localhost:8000")  
  
   if err != nil {  
      fmt.Println("Dial err", err)  
   }  
  
   defer conn.Close()  // 结束时,关闭连接  
  
   // 发送数据  
   _, err = conn.Write([]byte("Are u ready?"))  
  
   if err != nil {  
      fmt.Println("Write err:", err)  
      return  
   }  
}

1.2 并发服务

并发服务端:

Accept()函数的作用是等待客户端的链接,如果客户端没有链接,该方法会阻塞。如果有客户端链接,那么该方法返回一个Socket负责与客户端进行通信。所以,每来一个客户端,该方法就应该返回一个Socket与其通信,因此,可以使用一个死循环,将Accept()调用过程包裹起来。

需要注意的是,实现并发处理多个客户端数据的服务器,就需要针对每一个客户端连接,单独产生一个Socket,并创建一个单独的goroutine与之完成通信。

在判断客户端数据是否为“exit”字符串时,要注意,客户端会自动的多发送2个字符:$“\r\n”$(这在windows系统下代表回车、换行)

服务端代码:

package main  
  
import (  
   "fmt"  
   "net"   "strings")  
  
  
func main() {  
   // 创建监控  
   listener, err := net.Listen("tcp", "localhost:8000")  
   if err != nil {  
      fmt.Println("listen err:", err)  
      return  
   }  
  
   defer listener.Close()  // 主协程结束时,关闭listener  
  
   for {  
      // 等待客户端连接请求  
      conn, err := listener.Accept()  
  
      if err != nil {  
         fmt.Println("accpet err:", err)  
         return  
      }  
  
      // 处理用户请求,新建一个协程  
      go HandleConn(conn)  
   }  
}  
  
// 处理用户请求  
func HandleConn(conn net.Conn) {  
   // 函数调用完毕,自动关闭conn  
   defer conn.Close()  
  
   // 获取客户端发过来的网址信息  
   addr := conn.RemoteAddr().String()  
   fmt.Println(addr, "connect successful")  
  
   buf := make([]byte, 2048)  
  
   for {  
      // 读取用户数据  
      n, err := conn.Read(buf)  
      if err != nil {  
         fmt.Println("err=", err)  
         return  
      }  
  
      fmt.Printf("[%s]: %s\n",  addr,  string(buf[:n]))  
      fmt.Println("len = ", len(string(buf[:n])))  
  
      //if string(buf[:n-1]) == "exit" // nc测试,发送时,只有/n  
      if string(buf[:n-2]) == "exit" {  
         fmt.Println(addr, "exit")  
         return  
      }  
  
      // 将数据转化为大写,再给用户发送  
      conn.Write([]byte(strings.ToUpper(string(buf[:n]))))  
   }  
}

并发客户端:

客户端不仅需要持续的向服务端发送数据,同时也要接收从服务端返回的数据。因此可将发送和接收放到不同的协程中。

主协程循环接收服务器回发的数据(该数据应已转换为大写),并打印至屏幕;子协程循环从键盘读取用户输入数据,写给服务器。读取键盘输入可使用 os.Stdin.Read(str)。定义切片str,将读到的数据保存至str中。

这样,客户端也实现了多任务。

package main  
  
import (  
   "fmt"  
   "net"   "os")  
  
func main() {  
   // 主动发送连接请求  
   conn, err := net.Dial("tcp", "localhost:8000")  
  
   if err != nil {  
      fmt.Println("Dial err", err)  
   }  
  
   defer conn.Close()  // 客户端终止时,关闭于服务器通讯的socket  
  
   // 启动子协程: 接受用户键盘输入发送给服务端  
   go func() {  
	  // 创建用于存储用户键盘输入数据的切片缓冲区
      str := make([]byte, 1024)    
  
      for {  // 反复读取  
         n, err := os.Stdin.Read(str)  // 获取用户键盘输入(阻塞)  
         if err != nil {  
            fmt.Println("os.Stdin.Read err:", err)  
            return  
         }  
  
         // 从键盘读到的数据,发送给服务端  
         _, err = conn.Write(str[:n])  
         if err != nil {  
            fmt.Println("conn.Write err:", err)  
            return  
         }  
      }  
   }()  
  
   // 主协程: 接受服务端数据,进行打印输出  
   buf := make([]byte, 1024)  // 定义用于存储服务器回发数据的切片缓冲区  
   for {  
      n, err := conn.Read(buf)  // 从通信socket中读数据,存入切片缓冲区(阻塞)  
      if err != nil {  
         fmt.Println("conn.Read err:", err)  
         return  
      }  
  
      fmt.Printf("服务器回发: %s\n", string(buf[:n]))  
   }  
  
}

标签:err,第十一章,fmt,编程,网络,Println,buf,conn,客户端
From: https://www.cnblogs.com/yangyi215/p/17284410.html

相关文章

  • 第七章:并发编程
    第七章:并发编程目录第七章:并发编程一、并发与并行二、Go协程(Goroutine)1Go协程介绍2启动Go协程3GMP调度模型三、信道(Channel)1信道使用2死锁现象3单向信道【了解】4关闭信道5循环信道四、缓冲信道1缓冲信道2WaitGroup五、select六、mutex七、异常处理一、并发与并行并......
  • docker 网络介绍
     版权声明:本文为CSDN博主「逆袭的小学生」的原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/q610376681/article/details/90483576 上面我们只运行了nginx,并没有用浏览器进行访问,这里我们尝试用浏览器访问,但是之前我......
  • 智安网络|2023年网络安全未来的发展趋势
    随着“云大物移智”技术的不断成熟,互联网与物联网技术的不断融合,未来将有越来越多的物联网设备接入互联网,物联网产业将在中国蓬勃发展。目前,我国已出台了大量政策法规,引导和规范我国物联网产业的发展,并鼓励企业加大研发力度,努力将我国物联网产业发展成为全球领先的高科技产业。为了......
  • 06-网络安全-kail linux渗透测试(基础篇)
    渗透测试是一个非常广的课程,我们首先要做的是在某个方向精通,再在其他方面也要有涉猎。大部分的漏洞是国外挖掘的。一、推荐研究书籍:Metasploit浚透测试指南》肯尼(行业经典)  诸葛建伟翻译《Metasloit渗透测试魔鬼训练营》诸葛建伟(国内经典)《网络攻击技术与实践》诸葛建伟......
  • 我的第一个win32汇编程序
    .386.ModelFlat,stdcalloptioncasemap:none;头文件包含includewindows.incincludekernel32.incincludelibkernel32.libincludeuser32.incincludelibuser32.libincludegdi32.incincludelibgdi32.lib;数据段定义.datahInstancedd......
  • 函数式编程-高阶函数
    函数本身也可以赋值给变量,即:变量可以指向函数  那么函数名是什么呢?函数名其实是指向函数的变量!对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数! 既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函......
  • 编程里同步和异步的选择
    同步是指方法调用后必须等到返回才会执行后续代码异步是方法调用没等到返回也可以继续执行后续代码在java中如果是多线程,而各线程间会公用一个变量时,需要使用同步来保证线程安全,否则异步就是最好的在前端js中,一般http请求都是默认异步的,允许在发送http请求时执行其他函数,这样......
  • windows 10 系统 和 VMware Workstation 虚拟机网络互通设置
    windows10系统和VMwareWorkstation虚拟机网络互通设置 1,虚拟机设置网卡地址网关地址子网掩码2,VMwareWorkstation的编辑-虚拟网络编辑器,单击进入配置,为NAT类型。3,本地笔记本电脑的虚拟网卡配置地址网关掩码4,本地笔记本电脑使用secureCRT和winscp测试,连接和上传文件都OK......
  • 零基础Go语言从入门到精通(数据库编程:02-Gorm 操作 MySQL 数据库)
    gin-gorm-api-example/main.goatmaster·cgrant/gin-gorm-api-example·GitHubhttps://github.com/cgrant/gin-gorm-api-example/blob/master/main.goGorm介绍ThefantasticORMlibraryforGolangGo语言的超棒的ORM类库功能强大:全功能ORM(几乎)关联(包含一个,包含多个,属......
  • 网络原理与网络编程
     io模型有哪些网络io模型?哪些网络操作可以是异步的?常见的网络IO模型有:同步阻塞IO,同步非阻塞IO,多路复用IO和异步IO。异步网络操作包括:连接请求,数据发送和数据接收。(不确定)select/poll/epollselect/poll与epoll区别select和poll是两个系统调用,用于监视多个......