golang实现tcp客户端服务端程序
服务端代码:
package main
import (
"bufio"
"errors"
"flag"
"fmt"
"net"
"os"
"strconv"
)
// 指定一个命令行参数的名字
var port int
func Init() {
flag.IntVar(&port, "port", 8081, "set your server port")
}
func main() {
// 初始化命令行变量
Init()
flag.Parse()
// 监听端口
portStr := strconv.Itoa(port)
if portStr == "" {
fmt.Println("端口不正确,请确认")
return
}
listen, err := net.Listen("tcp", ":" + portStr)
if err != nil {
fmt.Println("监听端口" + portStr + "失败", err)
}
fmt.Println("监听" + portStr + "成功!")
for {
// 等待连接
conn, err := listen.Accept()
if err != nil {
fmt.Println("建立连接失败了")
}
fmt.Println("建立连接成功了")
// STEP - 1 处理发送消息
go func(conn net.Conn) {
handleSend(conn)
}(conn)
// STEP - 2 处理接收消息
// 必须要这个for 保持程序一直处于唤醒状态,一直读取conn里面的流
var receiveError error
for {
//go func(conn net.Conn) {
receiveError= handleReceive(conn)
if receiveError !=nil {
break
}
//}(conn)
}
if receiveError != nil {
break
}
}
}
func handleReceive(conn net.Conn) error{
//fmt.Println("handleReceive Method")
buff := make([]byte, 4096)
cnt, err := conn.Read(buff)
if cnt == 0 || err != nil {
fmt.Println("[WARN]-----断开连接------")
fmt.Println("[WARN]------END--------")
return errors.New("连接错误")
}
receiveData := string(buff)
fmt.Println("你收到了消息:", receiveData)
return nil
}
func handleSend(conn net.Conn) {
// 读取命令行里面的字符
//fmt.Println("handleSend Method")
r := bufio.NewReader(os.Stdin)
var line string
for {
fmt.Println("Send Message->")
rawLineBytes, _, _ := r.ReadLine()
line = string(rawLineBytes)
if len(line) < 1 {
continue
}
// 发送
fmt.Println("你发送了数据: [YOU]:" + line)
//conn.Write([]byte("[SERVER]: " + line))
_, err := fmt.Fprintf(conn, "[SERVER]: " + line)
if err != nil {
fmt.Println("发送数据失败")
}
}
}
启动代码:
```go
go run main.go -port=8081
客户端代码:
package main
import (
"bufio"
"errors"
"flag"
"fmt"
"io"
"net"
"os"
"time"
)
var serverPort int
var serverIP string
func Init() {
flag.IntVar(&serverPort, "serverPort", 8081, "set the server PORT you connect with")
flag.StringVar(&serverIP, "serverIP", "127.0.0.1", "set the server IP you will connect with")
}
func main() {
// 初始化命令行参数
Init()
flag.Parse()
// 连接server端
serverAddress := fmt.Sprintf("%s:%d", serverIP, serverPort)
conn, err := net.DialTimeout("tcp", serverAddress, time.Second * 3)
// 连接失败
if err != nil {
fmt.Println(fmt.Sprintf("连接[%s]失败了", serverAddress))
return
}
// 连接成功
fmt.Println(fmt.Sprintf("建立连接成功了[%s] !", serverAddress))
// 往conn这个写一个消息
fmt.Fprintf(conn, "HEAD / HTTP/1.0\r\n\r\n")
// STEP - 1 处理发送消息
go func(conn net.Conn) {
handleSend(conn)
}(conn)
// STEP - 2 处理接收消息
// 必须要这个for 保持程序一直处于唤醒状态,一直读取conn里面的流
for {
err := handleReceive(conn)
if err != nil {
break
}
}
}
func handleReceive(conn net.Conn) error {
//fmt.Println("handleReceive Method")
buff := make([]byte, 4096)
cnt, err := conn.Read(buff)
// 收到的数据长度为0
//if cnt == 0 || err != nil {
if err != nil {
fmt.Println("断开连接")
fmt.Println("----------END-----------")
fmt.Println(err, cnt, err == io.EOF)
return errors.New("断开连接了")
}
fmt.Println("你收到了消息:", string(buff))
return nil
}
func handleSend(conn net.Conn) {
//fmt.Println("handleSend Method")
r := bufio.NewReader(os.Stdin)
var line string
for {
fmt.Println("Send Message->")
rawLineBytes, _, _ := r.ReadLine()
line = string(rawLineBytes)
if len(line) < 1 {
continue
}
fmt.Println("你发送了数据: [YOU]:" + line)
_, err := fmt.Fprintf(conn, "[CLIENT]: " + line)
if cnt == 0||err != nil {
fmt.Println("发送数据失败")
}
}
}
启动代码:
go run main.go -serverPort=8081 -serverIp=127.0.0.1
tips:
1, 这个简单的网络应用有几个关键点
A : for 循环 等待连接/ 等待用户从命令行输入
B :go routine 协程处理发送或者接受消息,因为这两个动作,都是需要程序block住,所以必须 要用go routine
2,注意启动的时候端口占用情况,也许8081被占用
3,go build 的时候,windows/mac/linux平台有不同的命令。(自行搜索下
还没有评论,来说两句吧...