Does anyone know how to create a SOCKET as returned by WSASocket() function in go programming language?
Using a normal syscall.Socket type syscall.Bind results in:
WSAENOTSOCK - Error 10038 - An operation was attempted on something that is not a socket. The specified socket parameter refers to a file, not a socket.
Thanks
We don't use such low level API, we use net.Dial. ex.
func main() {
var (
host = "127.0.0.1"
port = "9998"
remote = host + ":" + port
msg string = "test"
)
con, error := net.Dial("tcp4", remote)
if error != nil {
fmt.Printf("Host not found: %s\n", error)
os.Exit(1)
} else {
defer con.Close()
}
in, error := con.Write([]byte(msg))
if error != nil {
fmt.Printf("Error sending data: %s, in: %d\n", error, in)
os.Exit(2)
}
fmt.Println("Connection OK")
}
Or, you could trace the code $GOROOT/src/pkg/net/dial.go
Related
I'm now working with Golang to connect IBM Websphere MQ-ESB and libraries which I use to communicate with MQ-ESB are
https://github.com/ibm-messaging/mq-golang
https://github.com/ibm-messaging/mq-golang-jms20
Generally, it can send the messages to MQ-ESB , but when something wrong happen the error MQ Connection Broken. This cause my app could not any longer send the messages to the MQ-ESB. Restarting service is the way to solve this issue (but it is not the way solve). Anyone has ideas?
Thanks
This is code create mq connection
func NewIBMMQConnection(mqConnConfig *mqjms.ConnectionFactoryImpl) jms20subset.JMSContext {
if !viper.GetBool("mq.openconnection") {
return &mqjms.ContextImpl{}
}
logx.WithFields(logrus.Fields{
"queue manager": viper.GetString("mq.qManager"),
"host": viper.GetString("mq.host"),
"port": viper.GetInt("mq.port"),
"channel": viper.GetString("mq.qChannel"),
}).Infof("[CONFIG] [MDM IBMMQ]")
conn, exception := mqConnConfig.CreateContext()
if exception != nil {
if exception.GetLinkedError() != nil {
logx.Fatalf("new mdm mq error: %s", exception.GetLinkedError())
}
}
return conn
}
func NewIBMMQConfig() *mqjms.ConnectionFactoryImpl {
return &mqjms.ConnectionFactoryImpl{
QMName: viper.GetString("mq.qManager"),
Hostname: viper.GetString("mq.host"),
PortNumber: viper.GetInt("mq.port"),
ChannelName: viper.GetString("mq.qChannel"),
UserName: viper.GetString("mq.login"),
Password: viper.GetString("mq.pass"),
}
}
This is the code in main.go that instantiate the connection
func main() {
db := newGormDB()
defer closeDB(db)
mq := ibmmq.NewIBMMQConnection(ibmmq.NewIBMMQConfig())
defer mq.Close()
ibmmq := ibmmq.New(mq)
...
...
go startServer()
shutdown()
}
This is code produce message
func (i *IBMMQ) ProduceMSGToMQ(ctx context.Context, msg string) error {
logx.WithContext(ctx).Infof("Producing Message queueName: message: %s", msg)
err := i.producer.SendString(i.queueCDDEMoeny, msg)
if err != nil {
logx.WithSeverityError(ctx).Errorf("Send msg to mq error: %s", err.GetErrorCode()+"-"+err.GetReason()+"-"+err.GetLinkedError().Error())
return errors.New("Send msg to mq error: " + err.GetErrorCode() + "-" + err.GetReason() + "-" + err.GetLinkedError().Error())
}
return nil
}
I'm not a Go language expert, only an IBM MQ expert, but here goes (no pun intended!).
I don't see where you call your ProduceMSGToMQ function, but I imagine something like this:-
error := ibmmq.ProduceMSGToMQ(...)
if error != nil && (error.GetReason() == "MQRC_CONNECTION_BROKEN") {
mq := ibmmq.NewIBMMQConnection(ibmmq.NewIBMMQConfig())
}
Hope that helps a little.
We also had to restart service to restore connection on MQ client.
But the problem was resolved after setting the option to reconnect.
mqcno := ibmmq.NewMQCNO()
...
...
mqcno.Options = ibmmq.MQCNO_CLIENT_BINDING
mqcno.Options |= ibmmq.MQCNO_RECONNECT_Q_MGR
I use memcache for caching and the client I use is https://github.com/bradfitz/gomemcache. When I tried initiate new client with dummy/invalid server address and then pinging to it, it return no error.
package main
import (
"fmt"
m "github.com/bradfitz/gomemcache"
)
func main() {
o := m.New("dummy_adress")
fmt.Println(o.Ping()) // return no error
}
I think it suppose to return error as the server is invalid. What do I miss?
It looks like the New() call ignores the return value for SetServers:
func New(server ...string) *Client {
ss := new(ServerList)
ss.SetServers(server...)
return NewFromSelector(ss)
}
The SetServers() function will only set the server list to valid servers (in
your case: no servers) and the Ping() funtion will only ping servers that are
set, and since there are no servers set it doesn't really do anything.
This is arguably a feature; if you have 4 servers and one is down then that's
not really an issue. Even with just 1 server memcache is generally optional.
You can duplicate the New() logic with an error check:
ss := new(memcache.ServerList)
err := ss.SetServers("example.localhost:11211")
if err != nil {
panic(err)
}
c := memcache.NewFromSelector(ss)
err = c.Ping()
if err != nil {
panic(err)
}
Which gives:
panic: dial tcp 127.0.0.1:11211: connect: connection refused
Given the following gRPC server side code:
import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
....
)
....
func (s *Router) Assign(ctx context.Context, req *api.Request(*api.Response, error) {
return nil, status.Errorf(codes.PermissionDenied,
}
....
What is the recommended technique for asserting client side that the error is of code = codes.PermissionDenied ?
Let's say your server returns codes.PermissionDenined like this
...
return nil, status.Error(codes.PermissionDenied, "PERMISSION_DENIED_TEXT")
If your client is Golang as well can also use the status library function FromError to parse the error. I use a switch to determine the error code returned like so
// client
assignvar, err := s.MyFunctionCall(ctx, ...)
if err != nil {
if e, ok := status.FromError(err); ok {
switch e.Code() {
case codes.PermissionDenied:
fmt.Println(e.Message()) // this will print PERMISSION_DENIED_TEST
case codes.Internal:
fmt.Println("Has Internal Error")
case codes.Aborted:
fmt.Println("gRPC Aborted the call")
default:
fmt.Println(e.Code(), e.Message())
}
}
else {
fmt.Printf("not able to parse error returned %v", err)
}
}
You can also use status.Code, to directly check the error code without the need to get a Status value first. For example:
if err != nil {
switch status.Code(err) {
case codes.NotFound:
// handle not found
case codes.FailedPrecondition:
// handle failed precondition
default:
// handle other status codes
}
}
I'm trying to implement a websocket proxy server for GlassFish. If I try to connect more than one client I'm getting error:
ReadMessage Failed: websocket: close 1007 Illegal UTF-8 Sequence.
I'm sure the GlassFish server sending right data, because the same server works properly with another proxy server implemented with node.js.
func GlassFishHandler(conn *websocket.Conn){
defer conn.Close()
conn.SetReadDeadline(time.Now().Add(1000 * time.Second))
conn.SetWriteDeadline(time.Now().Add(1000 * time.Second))
fmt.Println("WS-GOLANG PROXY SERVER: Connected to GlassFish")
for {
messageType, reader, err := conn.NextReader()
if err != nil {
fmt.Println("ReadMessage Failed: ", err) // <- error here
} else {
message, err := ioutil.ReadAll(reader)
if (err == nil && messageType == websocket.TextMessage){
var dat map[string]interface{}
if err := json.Unmarshal(message, &dat); err != nil {
panic(err)
}
// get client destination id
clientId := dat["target"].(string)
fmt.Println("Msg from GlassFish for Client: ", dat);
// pass through
clients[clientId].WriteMessage(websocket.TextMessage, message)
}
}
}
}
Summing up my comments as an answer:
When you are writing to the client, you are taking the clientId from the GlassFish message, fetching the client from a map, and then writing to it - basically clients[clientId].WriteMessage(...).
While your map access can be thread safe, writing is not, as this can be seen as:
// map access - can be safe if you're using a concurrent map
client := clients[clientId]
// writing to a client, not protected at all
client.WriteMessage(...)
So what's probably happening is that two separate goroutines are writing to the same client at the same time. You should protect your client from it by adding a mutex in the WriteMessage method implementation.
BTW actually instead of protecting this method with a mutex, a better, more "go-ish" approach would be to use a channel to write the message, and a goroutine per client that consumes from the channel and writes to the actual socket.
So in the client struct I'd do something like this:
type message struct {
msgtype string
msg string
}
type client struct {
...
msgqueue chan *message
}
func (c *client)WriteMessage(messageType, messageText string) {
// I'm simplifying here, but you get the idea
c.msgqueue <- &message{msgtype: messageType, msg: messageText}
}
func (c *client)writeLoop() {
go func() {
for msg := ragne c.msgqueue {
c.actuallyWriteMessage(msg)
}
}()
}
and when creating a new client instance, just launch the write loop
I am having a hard time on this one because I cannot reproduce it locally. Intention originally was to test if a Redis connection is accessible from a go method if so continue else inform.
In my code:
if os.Getenv("REDISTOGO_URL") != "" {
host, password = parseRedistogoUrl()
} else {
host = "tcp:localhost:6379"
password = ""
}
db := 0
redis = godis.New(host, db, password)
// Try to set a "dummy" value:
err = redis.Set("INIT", time.Now().UTC())
With a Redis server available locally this executes without an error, but fails when on heroku.
What makes the problem more interesting is that if the last line (with err) is commented out then the next redis.Set in the program succeeds, which indicates that the server is accessible later on, but not "just after" the instanciation. Any ideas on how I should resolve this? Is godis.New(...) running asynchronously?
Update: This is the parsing function currently used from https://gist.github.com/TheDudeWithTheThing/6468746:
func ParseRedistogoUrl() (string, string) {
redisUrl := os.Getenv("REDISTOGO_URL")
redisInfo, _ := url.Parse(redisUrl)
server := redisInfo.Host
password := ""
if redisInfo.User != nil {
password, _ = redisInfo.User.Password()
}
return server, password
}
Rewriting the same method with redigo and https://github.com/soveran/redisurl:
// Gets redis instance from configuration parameters or environment's REDISTOGO_URL.
func redis_instance() (redis_con redis.Conn, err error) {
if os.Getenv("REDISTOGO_URL") != "" {
redis_con, err = redisurl.ConnectToURL(os.Getenv("REDISTOGO_URL"))
} else {
redis_con, err = redis.Dial("tcp", ":6379")
}
if err != nil {
return
}
// Try to set a "dummy" value, panic if redis is not accessible.
err = redis_con.Send("Set", "INIT", time.Now().UTC())
return
}
and from program's main:
redis, err := redis_instance()
redis.Send("Set", "SOMETHING", "ELSE")
if err != nil {
log.Critical("Cannot access Redis server")
log.Critical(fmt.Sprintf("%s", err))
os.Exit(2)
}
On logs I get the following output:
2014-09-16T18:15:10.084908+00:00 app[web.1]: 2014/09/16 18:15:10 CRITICAL003 Cannot access Redis server
2014-09-16T18:15:10.084974+00:00 app[web.1]: 2014/09/16 18:15:10 CRITICAL004 Connection error 10942
About redis access:
~ $ echo $REDISTOGO_URL
redis://redistogo:47███████████#hoki.redistogo.com:10███/
~ $ ping hoki.redistogo.com
bash: ping: command not found
~ $ nc hoki.redistogo.com 10███
flushdb
-NOAUTH Authentication required.
AUTH 47███████████
+OK
get XXX
$-1
set XXX 2
+OK
get XXX
$1
2