Unix Sockets in Go

转自:http://stackoverflow.com/questions/2886719/unix-sockets-in-go

Server:

package main



import "net"

import "fmt"



func echoServer(c net.Conn) {

    for {

        buf := make([]byte, 512)

        nr, err := c.Read(buf)

        if err != nil {

            return

        }



        data := buf[0:nr]

        fmt.Printf("Received: %v", string(data))

        _, err = c.Write(data)

        if err != nil {

            panic("Write: " + err.String())

        }

    }

}



func main() {

    l, err := net.Listen("unix", "/tmp/echo.sock")

    if err != nil {

        println("listen error", err.String())

        return

    }



    for {

        fd, err := l.Accept()

        if err != nil {

            println("accept error", err.String())

            return

        }



        go echoServer(fd)

    }

}

Client

package main



import (

    "net"

    "time"

    "io"

)



func reader(r io.Reader) {

    buf := make([]byte, 1024)

    for {

        n, err := r.Read(buf[:])

        if err != nil {

            return

        }

        println("Client got:", string(buf[0:n]))

    }

}



func main() {

    c,err := net.Dial("unix","", "/tmp/echo.sock")

    if err != nil {

        panic(err.String())

    }

    defer c.Close()



    go reader(c)

    for {

        _,err := c.Write([]byte("hi"))

        if err != nil {

            println(err.String())

            break

        }

        time.Sleep(1e9)

    }

}

 

转自:

Server:

package main



import (

    "fmt";

    "net";

    "log";

    "os";

    "container/list";

    "strings";

    "bytes";

    "flag";

)



// flag for debuging info. or a simple log

var debug = flag.Bool("d", false, "set the debug modus( print informations )")



type ClientChat struct {

    Name string;        // name of user

    IN chan string;     // input channel for to send to user

    OUT chan string;    // input channel from user to all

    Con *net.Conn;      // connection of client

    Quit chan bool;     // quit channel for all goroutines

    ListChain *list.List;    // reference to list

}



// read from connection and return true if ok

func (c *ClientChat) Read(buf []byte) bool{

    nr, err := c.Con.Read(buf);

    if err!=nil {

        c.Close();

        return false;

    }

    Log("Read():  ", nr, " bytes");

    return true;

}



// close the connection and send quit to sender

func (c *ClientChat) Close() {

    c.Quit<-true;

    c.Con.Close();

    c.deleteFromList();

}



// compare two clients: name and network connection

func (c *ClientChat) Equal(cl *ClientChat) bool {

    if bytes.Equal(strings.Bytes(c.Name), strings.Bytes(cl.Name)) {

        if c.Con == cl.Con {

            return true;

        }

    }

    return false;

}



// delete the client from list

func (c *ClientChat) deleteFromList() {

    for e := c.ListChain.Front(); e != nil; e = e.Next() {

        client := e.Value.(ClientChat);

        if c.Equal(&client) {

            Log("deleteFromList(): ", c.Name);

            c.ListChain.Remove(e);

        }

    }

}



// func Log(v ...): loging. give log information if debug is true

func Log(v ...) {

    if *debug == true {

        ret := fmt.Sprint(v);

        log.Stdoutf("SERVER: %s", ret);

    }

}



// func test(): testing for error

func test(err os.Error, mesg string) {

    if err!=nil {

        log.Stderr("SERVER: ERROR: ", mesg);

         os.Exit(-1);

    } else

        Log("Ok: ", mesg);

}



// handlingINOUT(): handle inputs from client, and send it to all other client via channels.

func handlingINOUT(IN <-chan string, lst *list.List) {

    for {

        Log("handlingINOUT(): wait for input");

        input := <-IN;  // input, get from client

        // send to all client back

        Log("handlingINOUT(): handling input: ", input);

        for value := range lst.Iter() {

            client := value.(ClientChat);

            Log("handlingINOUT(): send to client: ", client.Name);

            client.IN<- input;

        }  

    }

}



// clientreceiver wait for an input from network, after geting data it send to

// handlingINOUT via a channel.

func clientreceiver(client *ClientChat) {

    buf := make([]byte, 2048);



    Log("clientreceiver(): start for: ", client.Name);

    for client.Read(buf) {

        

        if bytes.Equal(buf, strings.Bytes("/quit")) {

            client.Close();

            break;

        }

        Log("clientreceiver(): received from ",client.Name, " (", string(buf), ")");

        send := client.Name+"> "+string(buf);

        client.OUT<- send;

        for i:=0; i<2048;i++ {

            buf[i]=0x00;

        }

    }    



    client.OUT <- client.Name+" has left chat";

    Log("clientreceiver(): stop for: ", client.Name);

}



// clientsender(): get the data from handlingINOUT via channel (or quit signal from

// clientreceiver) and send it via network

func clientsender(client *ClientChat) {

    Log("clientsender(): start for: ", client.Name);

    for {

        Log("clientsender(): wait for input to send");

        select {

            case buf := <- client.IN:

                Log("clientsender(): send to \"", client.Name, "\": ", string(buf));

                client.Con.Write(strings.Bytes(buf));

            case <-client.Quit:

                Log("clientsender(): client want to quit");

                client.Con.Close();

                break;

        }

    }

    Log("clientsender(): stop for: ", client.Name);

}



// clientHandling(): get the username and create the clientsturct

// start the clientsender/receiver, add client to list.

func clientHandling(con *net.Conn, ch chan string, lst *list.List) {

    buf := make([]byte, 1024);

    con.Read(buf);

    name := string(buf);

    newclient := &ClientChat{name, make(chan string), ch, con, make(chan bool), lst};



    Log("clientHandling(): for ", name);

    go clientsender(newclient);

    go clientreceiver(newclient);

    lst.PushBack(*newclient);

    ch<- name+" has joinet the chat";

}



func main() {

    flag.Parse();

    Log("main(): start");



    // create the list of clients

    clientlist := list.New();

    in := make(chan string);

    Log("main(): start handlingINOUT()");

    go handlingINOUT(in, clientlist);

    

    // create the connection

    netlisten, err := net.Listen("tcp", "127.0.0.1:9988");

    test(err, "main Listen");

    defer netlisten.Close();



    for {

        // wait for clients

        Log("main(): wait for client ...");

        conn, err := netlisten.Accept();

        test(err, "main: Accept for client");

        go clientHandling(&conn, in, clientlist);

    }

}

Server has three part which are running as goroutines and communicate via channels.
1) handlingINOUT() simple wait for input of clientreceiver() and send to all clientsender() which are in the list.
2) clientreceiver() wait for his data from client via networkconnection and send it to a inputchannel to handlingINOUT
3) clientsender() wait for data from channel and send it to client

every client connection get a his own clientreceiver/sender and a list entry. on disconnection the list entry will be deleted.

Client:

package main



import (

    "fmt";

    "net";

    "log";

    "os";

    "bytes";

    "bufio";

    "strings";

    "time";

    "flag";

)



var running bool;  // global variable if client is running



var debug = flag.Bool("d", false, "set the debug modus( print informations )")



// func Log(v ...): loging. give log information if debug is true

func Log(v ...) {

    if *debug == true {

        ret := fmt.Sprint(v);

        log.Stdoutf("CLIENT: %s", ret);

    }

}



// func test(): testing for error

func test(err os.Error, mesg string) {

    if err!=nil {

        log.Stderr("CLIENT: ERROR: ", mesg);

         os.Exit(-1);

    } else

        Log("Ok: ", mesg);

}



// read from connection and return true if ok

func Read(con *net.Conn) string{

    var buf [4048]byte;

    _, err := con.Read(&buf);

    if err!=nil {

        con.Close();

        running=false;

        return "Error in reading!";

    }

    str := string(&buf);

    fmt.Println();

    return string(str);

}



// clientsender(): read from stdin and send it via network

func clientsender(cn *net.Conn) {

    reader := bufio.NewReader(os.Stdin);

    for {

        fmt.Print("you> ");

        input, _ := reader.ReadBytes('\n');

        if bytes.Equal(input, strings.Bytes("/quit\n")) {

            cn.Write(strings.Bytes("/quit"));

            running = false;

            break;

        }

        Log("clientsender(): send: ", string(input[0:len(input)-1]));

        cn.Write(input[0:len(input)-1]);

    }

}



// clientreceiver(): wait for input from network and print it out

func clientreceiver(cn *net.Conn) {

    for running {

        fmt.Println(Read(cn));

        fmt.Print("you> ");

    }

}



func main() {

    flag.Parse();

    running = true;

    Log("main(): start ");

    

    // connect

    destination := "127.0.0.1:9988";

    Log("main(): connecto to ", destination);

    cn, err := net.Dial("tcp", "", destination);

    test(err, "dialing");

    defer cn.Close();

    Log("main(): connected ");



    // get the user name

    fmt.Print("Please give you name: ");

    reader := bufio.NewReader(os.Stdin);

    name, _ := reader.ReadBytes('\n');



    //cn.Write(strings.Bytes("User: "));

    cn.Write(name[0:len(name)-1]);



    // start receiver and sender

    Log("main(): start receiver");

    go clientreceiver(&cn);

    Log("main(): start sender");

    go clientsender(&cn);

    

    // wait for quiting (/quit). run until running is true

    for ;running; {

        time.Sleep(1*1e9);

    }

    Log("main(): stoped");

}

 

你可能感兴趣的:(socket)