socket :
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原义那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。
IP + PORT
ip:用来唯一标识一台主机
port:用来唯一标识一台主机上的服务
1.服务端处理流程:
a.监听端口
b.接收客户端连接
c.处理该连接
2.客户端处理流程
a.建立与服务端的连接
b.进行数据收发
c.关闭连接
服务端:
package main import( "fmt" "net" ) func main(){ fmt.Println("start server ...") lisen,err := net.Listen("tcp","0.0.0.0:8000") //监听主机和端口 ip+port if err != nil { fmt.Println("listen failed,err:",err) } for { conn,err := lisen.Accept() //conn 标识连接的每个客户端 // fmt.Printf("第一次打印%#v",conn) if err != nil { fmt.Println("accept failed ,err:",err) continue } go process(conn) //调用 goroutine处理请求,否则的话只有这个连接关闭才能处理别的连接 } } func process(conn net.Conn){ defer conn.Close() // fmt.Printf("第二次打印#v",conn) for { //循环读取数据 buf := make([]byte,512) _,err:= conn.Read(buf) //把数据读取存储到buf中 if err != nil { fmt.Println("read the data failed,err:",err) return } fmt.Println("read the string is",string(buf)) } }
客户端:
package main import( "fmt" "net" "bufio" "os" "strings" ) func main(){ conn, err := net.Dial("tcp","0.0.0.0:8000") //连接服务器端 if err != nil { fmt.Println("connection failed err:",err) return } defer conn.Close() inputReader := bufio.NewReader(os.Stdin) for { input,_ := inputReader.ReadString(' ') trimmedinput := strings.Trim(input," ") if trimmedinput == "Q" { return } _,err = conn.Write([]byte(trimmedinput)) //写数据给服务端 if err != nil { return } } }
上面实现了客户端向服务端发送数据,服务端读取数据,下面改一下,实现客户端与服务端的一个交互发送读取。
服务端代码 :
package main import( "fmt" "net" "bufio" "os" "strings" ) func main(){ fmt.Println("start server ...") lisen,err := net.Listen("tcp","0.0.0.0:8000") //监听主机和端口 ip+port if err != nil { fmt.Println("listen failed,err:",err) } for { conn,err := lisen.Accept() //conn 标识连接的每个客户端 // fmt.Printf("第一次打印%#v",conn) if err != nil { fmt.Println("accept failed ,err:",err) continue } go readprocess(conn) //调用 goroutine处理请求,否则的话只有这个连接关闭才能处理别的连接 go writeprocess(conn) } } func readprocess(conn net.Conn){ defer conn.Close() // fmt.Printf("第二次打印#v",conn) for { //循环读取数据 buf := make([]byte,512) _,err:= conn.Read(buf) //把数据读取存储到buf中 if err != nil { fmt.Println("read the data failed,err:",err) return } fmt.Println("from client:",string(buf)) } } func writeprocess(conn net.Conn){ defer conn.Close() fmt.Println("给客户端回复:") inputReader := bufio.NewReader(os.Stdin) for { input,_ := inputReader.ReadString(' ') trimmedinput := strings.Trim(input," ") _,err := conn.Write([]byte(trimmedinput)) //写数据给客户端 if err != nil { return } } }
客户端代码:
package main import( "fmt" "net" "bufio" "os" "strings" ) func main(){ conn, err := net.Dial("tcp","0.0.0.0:8000") //连接服务器端 if err != nil { fmt.Println("connection failed err:",err) return } defer conn.Close() fmt.Println("给服务端回复:") inputReader := bufio.NewReader(os.Stdin) for { input,_ := inputReader.ReadString(' ') trimmedinput := strings.Trim(input," ") if trimmedinput == "Q" { return } _,err = conn.Write([]byte(trimmedinput)) //写数据给服务端 if err != nil { return } go readprocess(conn) } } func readprocess(conn net.Conn){ defer conn.Close() for{ buf := make([]byte,512) _,err:= conn.Read(buf) //把数据读取存储到buf中 if err != nil { fmt.Println("read the data failed,err:",err) return } fmt.Println("from server:",string(buf)) } }