first commit
This commit is contained in:
commit
7b1c126acd
7
README.md
Normal file
7
README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# TCP CHAT
|
||||||
|
|
||||||
|
+ `/nick <name>` 设置自己的昵称
|
||||||
|
+ `/join <room>` 加入聊天房间
|
||||||
|
+ `/rooms` 获取聊天房间列表
|
||||||
|
+ `/msg <msg>` 发送消息
|
||||||
|
+ `/quit` 退出房间
|
||||||
71
client.go
Normal file
71
client.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
conn net.Conn
|
||||||
|
nick string
|
||||||
|
room *room
|
||||||
|
commands chan<- command
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) readInput() {
|
||||||
|
for {
|
||||||
|
msg, err := bufio.NewReader(c.conn).ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = strings.Trim(msg, "\r\n")
|
||||||
|
args := strings.Split(msg, " ")
|
||||||
|
cmd := strings.TrimSpace(args[0])
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case "/nick":
|
||||||
|
c.commands <- command{
|
||||||
|
id: CMD_NICK,
|
||||||
|
client: c,
|
||||||
|
args: args,
|
||||||
|
}
|
||||||
|
case "/join":
|
||||||
|
c.commands <- command{
|
||||||
|
id: CMD_JOIN,
|
||||||
|
client: c,
|
||||||
|
args: args,
|
||||||
|
}
|
||||||
|
case "/rooms":
|
||||||
|
c.commands <- command{
|
||||||
|
id: CMD_ROOMS,
|
||||||
|
client: c,
|
||||||
|
args: args,
|
||||||
|
}
|
||||||
|
case "/msg":
|
||||||
|
c.commands <- command{
|
||||||
|
id: CMD_MSG,
|
||||||
|
client: c,
|
||||||
|
args: args,
|
||||||
|
}
|
||||||
|
case "/quit":
|
||||||
|
c.commands <- command{
|
||||||
|
id: CMD_QUIT,
|
||||||
|
client: c,
|
||||||
|
args: args,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
c.err(fmt.Errorf("unknown command %s", cmd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) err(err error) {
|
||||||
|
c.conn.Write([]byte("ERR: " + err.Error() + "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) msg(msg string) {
|
||||||
|
c.conn.Write([]byte("> " + msg + "\n"))
|
||||||
|
}
|
||||||
17
command.go
Normal file
17
command.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type commandId int
|
||||||
|
|
||||||
|
const (
|
||||||
|
CMD_NICK = iota
|
||||||
|
CMD_JOIN
|
||||||
|
CMD_ROOMS
|
||||||
|
CMD_MSG
|
||||||
|
CMD_QUIT
|
||||||
|
)
|
||||||
|
|
||||||
|
type command struct {
|
||||||
|
id commandId
|
||||||
|
client *client
|
||||||
|
args []string
|
||||||
|
}
|
||||||
28
main.go
Normal file
28
main.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := newServer()
|
||||||
|
go s.run()
|
||||||
|
|
||||||
|
linstener, err := net.Listen("tcp", ":8888")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to start server: %v", err)
|
||||||
|
}
|
||||||
|
defer linstener.Close()
|
||||||
|
log.Println("started server on :8888")
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, err := linstener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to accept connection: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
go s.newClient(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
16
room.go
Normal file
16
room.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
type room struct {
|
||||||
|
name string
|
||||||
|
members map[net.Addr]*client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *room) broadcast(c *client, msg string) {
|
||||||
|
for addr, m := range r.members {
|
||||||
|
if addr != c.conn.RemoteAddr() {
|
||||||
|
m.msg(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
109
server.go
Normal file
109
server.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type server struct {
|
||||||
|
rooms map[string]*room
|
||||||
|
commands chan command
|
||||||
|
}
|
||||||
|
|
||||||
|
func newServer() *server {
|
||||||
|
return &server{
|
||||||
|
rooms: make(map[string]*room),
|
||||||
|
commands: make(chan command),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) run() {
|
||||||
|
for cmd := range s.commands {
|
||||||
|
switch cmd.id {
|
||||||
|
case CMD_NICK:
|
||||||
|
s.nick(cmd.client, cmd.args)
|
||||||
|
case CMD_JOIN:
|
||||||
|
s.join(cmd.client, cmd.args)
|
||||||
|
case CMD_ROOMS:
|
||||||
|
s.listRooms(cmd.client, cmd.args)
|
||||||
|
case CMD_MSG:
|
||||||
|
s.msg(cmd.client, cmd.args)
|
||||||
|
case CMD_QUIT:
|
||||||
|
s.quit(cmd.client, cmd.args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) newClient(conn net.Conn) {
|
||||||
|
log.Printf("new client has connected: %s", conn.RemoteAddr().String())
|
||||||
|
|
||||||
|
c := &client{
|
||||||
|
conn: conn,
|
||||||
|
nick: "anonymous",
|
||||||
|
commands: s.commands,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.readInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) nick(c *client, args []string) {
|
||||||
|
c.nick = args[1]
|
||||||
|
c.msg(fmt.Sprintf("all right, I will call you %s", c.nick))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) join(c *client, args []string) {
|
||||||
|
roomName := args[1]
|
||||||
|
|
||||||
|
r, ok := s.rooms[roomName]
|
||||||
|
if !ok {
|
||||||
|
r = &room{
|
||||||
|
name: roomName,
|
||||||
|
members: make(map[net.Addr]*client),
|
||||||
|
}
|
||||||
|
s.rooms[roomName] = r
|
||||||
|
}
|
||||||
|
|
||||||
|
r.members[c.conn.RemoteAddr()] = c
|
||||||
|
|
||||||
|
s.quitCurrentRoom(c)
|
||||||
|
c.room = r
|
||||||
|
|
||||||
|
r.broadcast(c, fmt.Sprintf("%s has joined the room", c.nick))
|
||||||
|
c.msg(fmt.Sprintf("Wecome to %s", r.name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) listRooms(c *client, args []string) {
|
||||||
|
var rooms []string
|
||||||
|
for name := range s.rooms {
|
||||||
|
rooms = append(rooms, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.msg(fmt.Sprintf("available rooms are: %s", strings.Join(rooms, ", ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) msg(c *client, args []string) {
|
||||||
|
if c.room == nil {
|
||||||
|
c.err(errors.New("you must join the room first"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.room.broadcast(c, strings.Join(args[1:], " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) quit(c *client, args []string) {
|
||||||
|
log.Printf("client has disconnection: %s", c.conn.RemoteAddr().String())
|
||||||
|
|
||||||
|
s.quitCurrentRoom(c)
|
||||||
|
c.msg("sad to see you go :(")
|
||||||
|
c.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) quitCurrentRoom(c *client) {
|
||||||
|
if c.room != nil {
|
||||||
|
delete(c.room.members, c.conn.RemoteAddr())
|
||||||
|
c.room.broadcast(c, fmt.Sprintf("%s has left the room", c.nick))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user