您的位置:首页 > 理论基础 > 计算机网络

Go语言简单的TCP编程

2013-09-17 23:36 495 查看

前期准备

需要
import "net"


IP
类型,其中一个重要的方法是
IP.ParseIP(ipaddr string)
来判断是否是合法的IP地址

TCP Client

func (c *TCPConn) Write(b []byte) (n int, err os.Error)
用于发送数据,返回发送的数据长度或者返回错误,是
TCPConn
的方法

func (c *TCPConn) Read(b []byte) (n int, err os.Error)
用于接收数据,返回接收的长度或者返回错误,是
TCPConn
的方法

TCPAddr
类型,保存TCP的地址信息,包括地址和端口

type TCPAddr struct {
IP IP
Port int
}


func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error)
获取一个
TCPAddr
,参数都是
string
类型,net是个
const string
,包括
tcp4
,
tcp6
,
tcp
一般使用
tcp
,兼容v4和v6,
addr
表示ip地址,包括端口号,如
www.google.com:80
之类的

func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error)
用来连接(connect)到远程服务器上,net表示协议方式,
tcp
,
tcp4
或者
tcp6
laddr
表示本机地址,一般为
nil
raddr
表示远程地址,这里的
laddr
raddr
都是
TCPAddr
类型的,一般是上一个函数的返回值。

作为一个TCP的客户端,基本的操作流程如下:

service="www.google.com:80"
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
conn, err := net.DialTCP("tcp", nil, tcpAddr)
_, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))
_, err = conn.Read(b) / result, err := ioutil.ReadAll(conn)


TCP Server

func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error)
用来监听端口,
net
表示协议类型,
laddr
表示本机地址,是
TCPAddr
类型,注意,此处的laddr包括端口,返回一个
*TCPListener
类型或者错误

func (l *TCPListener) Accept() (c Conn, err os.Error)
用来返回一个新的连接,进行后续操作,这是
TCPListener
的方法,一般
TCPListener
从上一个函数返回得来。

服务器的基本操作流程为:

service:=":9090"
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
l,err := net.ListenTCP("tcp",tcpAddr)
conn,err := l.Accept()
go Handler(conn) //此处使用go关键字新建线程处理连接,实现并发


一个例子

需求

实现一个公共聊天服务器。

服务器接收客户端的信息

接收完以后将客户端的信息发送到所有的客户端上

客户端使用
/quit
退出聊天

只使用一套代码,通过命令行参数启动服务器还是客户端

实现:

package main

import(
"fmt"
"os"
"net"
)

////////////////////////////////////////////////////////
//
//错误检查
//
////////////////////////////////////////////////////////
func checkError(err error,info string) (res bool) {

if(err != nil){
fmt.Println(info+"  " + err.Error())
return false
}
return true
}

////////////////////////////////////////////////////////
//
//服务器端接收数据线程
//参数:
//		数据连接 conn
//		通讯通道 messages
//
////////////////////////////////////////////////////////
func Handler(conn net.Conn,messages chan string){

fmt.Println("connection is connected from ...",conn.RemoteAddr().String())

buf := make([]byte,1024)
for{
lenght, err := conn.Read(buf)
if(checkError(err,"Connection")==false){
conn.Close()
break
}
if lenght > 0{
buf[lenght]=0
}
//fmt.Println("Rec[",conn.RemoteAddr().String(),"] Say :" ,string(buf[0:lenght]))
reciveStr :=string(buf[0:lenght])
messages <- reciveStr

}

}

////////////////////////////////////////////////////////
//
//服务器发送数据的线程
//
//参数
//		连接字典 conns
//		数据通道 messages
//
////////////////////////////////////////////////////////
func echoHandler(conns *map[string]net.Conn,messages chan string){

for{
msg:= <- messages
fmt.Println(msg)

for key,value := range *conns {

fmt.Println("connection is connected from ...",key)
_,err :=value.Write([]byte(msg))
if(err != nil){
fmt.Println(err.Error())
delete(*conns,key)
}

}
}

}

////////////////////////////////////////////////////////
//
//启动服务器
//参数
//	端口 port
//
////////////////////////////////////////////////////////
func StartServer(port string){
service:=":"+port //strconv.Itoa(port);
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
checkError(err,"ResolveTCPAddr")
l,err := net.ListenTCP("tcp",tcpAddr)
checkError(err,"ListenTCP")
conns:=make(map[string]net.Conn)
messages := make(chan string,10)
//启动服务器广播线程
go echoHandler(&conns,messages)

for  {
fmt.Println("Listening ...")
conn,err := l.Accept()
checkError(err,"Accept")
fmt.Println("Accepting ...")
conns[conn.RemoteAddr().String()]=conn
//启动一个新线程
go Handler(conn,messages)

}

}

////////////////////////////////////////////////////////
//
//客户端发送线程
//参数
//		发送连接 conn
//
////////////////////////////////////////////////////////
func chatSend(conn net.Conn){

var input string
username := conn.LocalAddr().String()
for {

fmt.Scanln(&input)
if input == "/quit"{
fmt.Println("ByeBye..")
conn.Close()
os.Exit(0);
}

lens,err :=conn.Write([]byte(username + " Say :::" + input))
fmt.Println(lens)
if(err != nil){
fmt.Println(err.Error())
conn.Close()
break
}

}

}

////////////////////////////////////////////////////////
//
//客户端启动函数
//参数
//		远程ip地址和端口 tcpaddr
//
////////////////////////////////////////////////////////
func StartClient(tcpaddr string){

tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpaddr)
checkError(err,"ResolveTCPAddr")
conn, err := net.DialTCP("tcp", nil, tcpAddr)
checkError(err,"DialTCP")
//启动客户端发送线程
go chatSend(conn)

//开始客户端轮训
buf := make([]byte,1024)
for{

lenght, err := conn.Read(buf)
if(checkError(err,"Connection")==false){
conn.Close()
fmt.Println("Server is dead ...ByeBye")
os.Exit(0)
}
fmt.Println(string(buf[0:lenght]))

}
}

////////////////////////////////////////////////////////
//
//主程序
//
//参数说明:
//	启动服务器端:  Chat server [port]				eg: Chat server 9090
//	启动客户端:    Chat client [Server Ip Addr]:[Server Port]  	eg: Chat client 192.168.0.74:9090
//
////////////////////////////////////////////////////////
func main(){

if len(os.Args)!=3  {
fmt.Println("Wrong pare")
os.Exit(0)
}

if os.Args[1]=="server" && len(os.Args)==3 {

StartServer(os.Args[2])
}

if os.Args[1]=="client" && len(os.Args)==3 {

StartClient(os.Args[2])
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: