conhecimento TCP / IP saltou a cerca de resumir os pontos
- Apreciado que a teoria do modelo de sete camadas OSI, ser entendido que o modelo TCP / IP estrutura de quatro camadas: a camada de aplicação, camada de transporte, camada de rede, camada de interface de rede.
- protocolo TCP / IP contém uma grande quantidade de protocolos, TCP e IP são apenas dois entre os mais representativos.
- estrutura C / S: os representantes IM pertencem a programação TCP SOCKET; B / S estrutura: representativas shopping JD, pertencente ao programa de HTTP, o TCP é parte de protocolo HTTP / IP.
- Sobre seção de rede, você deve ser um profundo entendimento do TCP / IP, a fim de melhor desenvolvimento de follow-up, o Departamento não irá repeti-los.
- Porto menos aberta, para abrir mais de uma cópia do risco, o servidor pode abrir portas cada vez menos aberta, o sistema deve ser versão pura; single-porta correspondente a um único programa, não podem ser reutilizados;
TCP socket programação do lado do cliente e do lado do servidor
- Multi-Cliente geralmente correspondem minoria Server.
- O fluxo de processamento do servidor:
porta de escuta (Listening);
receber pedidos de clientes TCP para estabelecer cliente e do lado do servidor ligação;
criar goroutine, o processamento do pedido link (Cliente através do envio de um pacote de solicitação). - Cliente Fluxo do processo:
estabelecimento da ligação e lateral de serviço (escuta na porta servidor vinculado porta aleatória-definido);
dados de solicitação de envio, o servidor de recebimento retorna os resultados de dados;
ligações estreitas (TCP respondendo por consumo de recursos, similar para abrir o arquivo que você deseja adiar desligado para evitar memória vazamento);
prática, o cliente e servidor para escrever um modelo C / S para transmitir e receber informações, um terminal de entrada, um terminal de saída
análise do lado do servidor e comentários:
package main
import (
"fmt"
"net"
)
func recv(conn net.Conn) {
//循环接收客户端发送来的请求
defer conn.Close() //如果不关闭服务器因为连接没有释放,后续客户端无法登陆了
for {
//创建一个新的切片
buf := make([]byte,1024)
//fmt.Printf("服务器在等待客户端%v发送信息\n",conn.RemoteAddr().String())
n, err := conn.Read(buf) //如果客户端conn不发信息,没有write操作,会一直阻塞,优化做一个timeout
if err != nil {
return
}
//显示信息到服务器终端,buf[:n]是真正读到的信息,否则切片后一大串东西都会出来,很乱套
fmt.Print(string(buf[:n]))
}
}
func main() {
/*
需求分析:
1. 服务端: 监听端口6666,要为多个客户端提供服务;
不能阻塞,所以每个客户端请求都用一个goroutine提供服务;
MPG模型,P调度处一个goroutine为客户端x提供服务,实际上是不同的G在为不同的client提供服务;
全部开协程,就变成了并发的了,同时进行请求响应。
2. 客户端: 端口随机,通过Socket发送请求指定到服务器端6666端口
*/
/*
服务器端代码编写: package net中
大部分使用者只需要Dial、Listen和Accept函数提供的基本接口,以及相关的Conn和Listener接口。
crypto/tls包提供了相同的接口和类似的Dial和Listen函数。
Dial函数和服务端建立连接,Listen函数创建的服务端。
*/
listener, err := net.Listen("tcp", "0.0.0.0:6666") //返回listener为接口类型资源
if err != nil {
fmt.Println("连接错误,程序退出") //监听都错误,后面不用玩了
return
}
defer listener.Close() //类似文件,及时关闭
//监听成功,获得ln为&{0xc00008e000}
fmt.Printf("监听成功,获得lnr为%v\n",listener) //相当于监听成功就跑路了,所以需要for循环。
for {
//关于conn接口类型资源拥有的方法:
/*
// Read从连接中读取数据
// Read方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
Read(b []byte) (n int, err error)
// Write从连接中写入数据
// Write方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
Write(b []byte) (n int, err error)
// Close方法关闭该连接
// 并会导致任何阻塞中的Read或Write方法不再阻塞并返回错误
Close() error
// 返回本地网络地址
LocalAddr() Addr
// 返回远端网络地址
RemoteAddr() Addr
*/
conn, err := listener.Accept() // Accept等待并返回下一个连接到该接口的连接, conn为接口类型实例,通俗点,通信连接线对象
if err != nil {
continue //这里出错了不要使用return或者break,因为并发连接千万,不能因为一个就终止服务器监听
} else {
fmt.Printf("Accept() successed conn = %v\n",conn)
fmt.Printf("客户端IP= %v\n",conn.RemoteAddr().String()) // 返回远端网络地址
}
//起一个协程为连接进来的客户端提供一对一服务,监听是通过服务器主程序
// 端口仍然是同一个,类似前台,但是提供读写等,为客户端服务的是协程
go recv(conn)
}
}
Cliente Cliente e anotação análise:
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
//客户端使用net.Dial()来完成,无需要监听,只需要conn即可
conn, err := net.Dial("tcp","127.0.0.1:6666")
if err != nil {
fmt.Println("连接错误,错误原因为:",err,"请重新连接")
return
} else {
fmt.Println("conn is successfully connect~",conn)
}
reader := bufio.NewReader(os.Stdin)
for {
ln, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Reading String Error!")
}
ln = strings.Trim(ln,"\r\n")
if ln == "exit" {
fmt.Println("客户端由于exit命令退出")
break
}
_, err = conn.Write([]byte(ln + "\n"))
if err != nil {
fmt.Println("Writing error!",err)
}
}
}