func (c *TCPConn) Write(b []byte) (n int, err os.Error)
用于發(fā)送數(shù)據(jù),返回發(fā)送的數(shù)據(jù)長度或者返回錯誤,是TCPConn的方法func (c *TCPConn) Read(b []byte) (n int, err os.Error)
用于接收數(shù)據(jù),返回接收的長度或者返回錯誤,是 TCPConn 的方法 type TCPAddr struct {
IP IP
Port int
}
func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error)
獲取一個 TCPAddr,參數(shù)都是 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)到遠(yuǎn)程服務(wù)器上,net 表示協(xié)議方式,tcp,tcp4 或者 tcp6,laddr 表示本機地址,一般為 nil,raddr 表示遠(yuǎn)程地址,這里的 laddr 和 raddr 都是 TCPAddr 類型的,一般是上一個函數(shù)的返回值。 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)
func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error)
用來監(jiān)聽端口,net 表示協(xié)議類型,laddr 表示本機地址,是 TCPAddr 類型,注意,此處的 laddr 包括端口,返回一個*TCPListener
類型或者錯誤func (l *TCPListener) Accept() (c Conn, err os.Error)
用來返回一個新的連接,進(jìn)行后續(xù)操作,這是 TCPListener 的方法,一般 TCPListener 從上一個函數(shù)返回得來。
service:=":9090"
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
l,err := net.ListenTCP("tcp",tcpAddr)
conn,err := l.Accept()
go Handler(conn) //此處使用go關(guān)鍵字新建線程處理連接,實現(xiàn)并發(fā)
/quit
退出聊天實現(xiàn):
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
}
////////////////////////////////////////////////////////
//
//服務(wù)器端接收數(shù)據(jù)線程
//參數(shù):
// 數(shù)據(jù)連接 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
}
}
////////////////////////////////////////////////////////
//
//服務(wù)器發(fā)送數(shù)據(jù)的線程
//
//參數(shù)
// 連接字典 conns
// 數(shù)據(jù)通道 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)
}
}
}
}
////////////////////////////////////////////////////////
//
//啟動服務(wù)器
//參數(shù)
// 端口 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)
//啟動服務(wù)器廣播線程
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)
}
}
////////////////////////////////////////////////////////
//
//客戶端發(fā)送線程
//參數(shù)
// 發(fā)送連接 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
}
}
}
////////////////////////////////////////////////////////
//
//客戶端啟動函數(shù)
//參數(shù)
// 遠(yuǎn)程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")
//啟動客戶端發(fā)送線程
go chatSend(conn)
//開始客戶端輪訓(xùn)
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]))
}
}
////////////////////////////////////////////////////////
//
//主程序
//
//參數(shù)說明:
// 啟動服務(wù)器端: 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])
}
}
主要知識點如下:
(1)代碼中包括了服務(wù)器和客戶端的內(nèi)容,如果是服務(wù)器,直接輸入./chat server 9090
即可,客戶端也很簡單,輸入./chat client :9090
就好;
(2)如果是客戶端,其實就包括了兩部分內(nèi)容,一部分是 chatSend 函數(shù),接受用戶的輸入;另一部分是connect 到 server,接受相關(guān)信息;
(3)如果是 server,稍微復(fù)雜一點,有三個部分組成。第一部分就是不停地 accept 各個客戶端;第二個就是為每一個客戶端創(chuàng)立 Handler 函數(shù),接受客戶端發(fā)來的信息;第三個就是 echoHandler 函數(shù),它的作用就是將從某一用戶接受過來的信息廣播給其他所有的客戶端,就是這么簡單。