前期准备


  • 需要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或者tcp6laddr表示本机地址,一般为nilraddr表示远程地址,这里的laddrraddr都是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])
} }

最新文章

  1. SQL多表查询
  2. WCF初探-27:WCF中的实例化
  3. eclipse快捷键以及使用技巧大全
  4. 黑马程序员+Winform基础(下)
  5. github图片
  6. OpenCV3编程入门笔记(2)计时函数、感兴趣区域RIO、分离/混合通道
  7. oc-类目、延展、协议
  8. Android 4.4 KitKat, the browser and the Chrome WebView
  9. .net后台 Silverlight 页面 动态设置 ASPX 页面 控件的Margin值(位置设置)
  10. CodeSmith 生成代码
  11. 锐捷Linux版的下载和使用(福大客户端)
  12. SWUST OJ(960)
  13. gitlab代码仓库迁移
  14. Centos 7 下创建LVM流程
  15. Gson解析复杂JSON字符串的两种方式
  16. java 报错及解决
  17. python小数的进位与舍去
  18. spring jpa和mybatis整合
  19. NHibernate实例
  20. Jmeter创建FTP测试计划

热门文章

  1. linux命令学习03-grep
  2. python-凯撒密码
  3. android XML格式颜色
  4. 图片和提交servlet的相对和绝对路径
  5. 【OpenGL游戏开发之三】OpenGl核心函数库汇总
  6. 理解Unity加载和内存管理
  7. [置顶] 自娱自乐6之Linux gadget驱动5(自编gadget驱动,包涵与之通讯的主机usb驱动,已调试通过)
  8. JavaScript单线程
  9. 在Oracle中使用sql获取数据库名称
  10. VS2010+Visual Assist X