I am writing an app taking advantage of Lua Socket lib. Here is a simple code snippet that describes my problem.
local com=require("socket");
local socket=com.tcp();
local hello="hi stack overflow";
local myIP="192.168.1.1";
local myPort = 2000;
local err = nil;
-- Main
while 1
if(~err) then
err = socket:send(hello);
else
if(socket:connect("myIP", myPort))) then
err = 1;
end -- second if
end -- first if
waitfor(10); -- wait for 10 sec.
do
(I actually didn't run this particular code but it is identical to the running code in my problem).
When I see that if socket is closed, this code cannot reopen it. I would have guessed once we grab the master TCP object we can open and close as we please.
I can force this code to work by repeating the socket.tcp() call however I suspect that leaves the previous object somewhere in memory and I want to avoid this.
Well, things that are wrong in your code (starting from the top)
It's a bad habbit reusing default module names like socket, it'll confuse people reading your code
While loop syntax is while <condition> do <statements> end
setting err to nil is useless in this case, as it does not exist in the snippet scope
it makes no sense to send to an unconnected master.
negation is done with not instead of ~
you pass the string "myIP" instead of the actual IP
then there's also a function socket.sleep() you might be interested in.
I'm wondering why you complicate the loop this way, and don't just use something like:
require("socket");
local soc=socket.tcp();
local hello="hi stack overflow";
local myIP="192.168.1.1";
local myPort = 2000;
local stat,err=socket:connect(myIP, myPort)
if not stat then
error(err)
else
-- Main
while not err do
err = socket:send(hello)
socket.sleep(10)
end
end
The connect call will never work as you are passing the string "myIP" not the variable myIP which contains your target Ip address.
Related
well hello there,
So I'll get right to the point..
Everyone knows that in Roblox you have a ReplicatedStorage (for Client and Server) and a ServerStorage (only for Server).
So I want to store all my assets in ServerStorage .. you know, since exploiters/hackers can't see the ServerStorage if they tried.
However my game has virtual worlds..meaning that the client sees different objects than the other clients at any given time, so I can't just load an object from a server scripts because then everyone will see it.
Heres the question: Can I perhaps set up a remote function that lets the Client invoke the Server, and then the Server returns a model object or its location or something like that? And can I then use the Client to load the model into the player's workspace?
^That way I can securely store my important game assets in the serverstorage
The answer to your question is "Yes, you can!"
First off, you're going to want to create a RemoteFunction in the ReplicatedStorage. Call this RemoteFunction, 'GetModel'
Now, we're going to set up a local script inside of the StarterPack. This local script should have the following code:
local RS = game:GetService("ReplicatedStorage")
local RF = RS:WaitForChild("GetModel")
local model = RF:InvokeServer("ModelName") -- This code can go anywhere you'd like it to go. 'ModelName' is the name of the model you want to get.
print(model.Name) -- This will print the model's name.
Alright, so we've setup our code to invoke the remotefunction. Now, let's make that RemoteFunction do something. We'll create a server script inside of ServerScriptService. Here's the code:
local RS = game:GetService("ReplicatedStorage")
local RF = RS:WaitForChild("GetModel")
RF.OnServerInvoke = function(player, modelName)
local model = game.ServerStorage:FindFirstChild(modelName)
if model == nil then
return nil
else
return model
end
end
Most of this is basic code, and from what you said in the question it seems you understand lua fine. Hope I helped you! :)
I'm trying to figure out how to implement unix sockets in crystal. I'd like to be able to send a name to a server app and have it return "Hello #{name}."
#server.cr
require "socket"
loop do
spawn do
server = UNIXServer.new("/tmp/myapp.sock")
name = server.gets
server.puts "Hello #{name}."
end
end
On the client I assume I could just have a loop that waits for standard in and sends it over the socket.
#client.cr
require "socket"
loop do
sock = UNIXSocket.new("/tmp/myapp.sock")
puts "What is your name?\n: "
name = gets
sock.puts name
puts sock.gets
sock.close
end
Obviously I'm missing something vital here, but I can't seem to find the right things in the documentation to fill in the blanks. What is the connections between UNIXServer and UNIXSocket? If someone could show me a working example of what I'm trying to do I would be forever grateful.
Update: Here's my Solution
It turns out that using UNIXServer and calling accept on it to create a socket solved my initial issue. After than I ran into the issue that all of the Fibers were using the same socket so closing one closed all of them. There's probably another solution but this works for me. Thanks to #RX14 for all the help.
#server.cr
require "socket"
server = UNIXServer.new("/tmp/cr.sock")
while sock = server.accept
proc = ->(sock : UNIXSocket) do
spawn do
name = sock.gets
unless name == "q"
puts name
sock.puts "Hello #{name}."
sock.close
else
server.close
exit
end
end
end
proc.call(sock)
end
#client.cr
require "socket"
UNIXSocket.open("/tmp/cr.sock") do |sock|
puts "What is your name?"
name = gets
sock.puts name
puts sock.gets
sock.close
end
You need to use either UNIXServer#accept or UNIXServer#accept? methods to accept a incoming connection.
# server.cr
require "socket"
def handle_connection(socket)
name = socket.gets
socket.puts "Hello #{name}."
end
server = UNIXServer.new("/tmp/myapp.sock")
while socket = server.accept
spawn handle_connection(socket)
end
# client.cr
require "socket"
UNIXSocket.open("/tmp/myapp.sock") do |sock|
puts "What is your name?\n: "
name = STDIN.gets
sock.puts name
puts sock.gets
end
Say I open a connection to a server like:
conn, _ := net.DialTimeout("tcp", "127.0.0.1:2121", 10000000)
and I do some stuff and then call
conn.Close()
that's option 1. But what if I don't call Close on the conn and just call
os.Exit(1)
leaving the connection still open. That's option 2. i.e. I'm trying to simulate a user uploading a file and either reaching the ending and really Closing the connection... or ending the stream being writen to the socket but never officially closing it.
Back on the server side, is there anyway to tell which event happened? The good Close or the bad one?
Does net.Listener have like some sort of callback to let me know. Because when I just call:
n, err := serverConn.Read()
I get an EOF err in either case, good or bad.
It depends on the operating system. The one you're on clearly does a graceful close for you if your process exits with an unclosed socket, so it is equivalent to 'good'. With the other kind you will get an ECONNRESET.
You should call Read like this:
var done,closeCh chan struct{}
func readLoop(c net.Conn) {
for {
n,err := conn.Read(buf)
// check n and err
close(closeCh)
// or
close(done)
}
}
func handle(conn net.Conn) {
go readLoop(conn)
select {
case <-closeCh:
println("closed")
case <-done:
println("done")
}
}
I know this isn't an answer but I can't comment and it's extremely frustrating because I tried to suggest an edit to just ask this question, and this app told me I couldn't after I wrote it. Please be merciful.
#EJP Can you provide a source? I know what you're saying is true for C but almost literally everything is safe to let the GC handle for closes on program termination in Go. I'd wager it has nothing to do with the OS (but I could be mistaken) as the GC probably handles closing the socket properly for you anyways (see all the libraries which explain "you can save time by ommiting 'Close' if the program execution is terminating"). I'm considering asking a question of how far that goes but I've run into exactly one case where it doesn't handle the cleanup (and it's certainly not in a standard lib).
I have an intermittent problem with a telnet based server on Unix (the problem crops up on both AIX and Linux).
The server opens two sockets, one to a client telnet session, and one to a program running on the same machine as the server. The idea is that the data is passed through the server to and from this program.
The current setup has a loop using select to wait for a "read" file descriptor to become available, then uses select to wait for a "write" file descriptor to become available.
Then the program reads from the incoming file descriptor, then processes the data before writing to the outgoing descriptor.
The snippet below shows what is going on. The problem is that very occasionally the read fails, with errno being set to ECONNRESET or ETIMEDOUT. Neither of these are codes documented by read, so where are they coming from?
The real question is, how can I either stop this happening, or handle it gracefully?
Could doing two selects in a row be the problem?
The current handling behaviour is to shut down and restart. One point to note is that once this happens it normally happens three or four times, then clears up. The system load doesn't really seem to be that high (it's a big server).
if (select(8, &readset, NULL, NULL, NULL) < 0)
{
break;
}
if (select(8, NULL, &writeset, NULL, NULL) < 0)
{
break;
}
if (FD_ISSET(STDIN_FILENO, &readset)
&& FD_ISSET(fdout, &writeset))
{
if ((nread = read(STDIN_FILENO, buff, BUFFSIZE)) < 0)
{
/* This sometimes fails with errno =
ECONNRESET or ETIMEDOUT */
break;
}
}
Look at the comments in http://lxr.free-electrons.com/source/arch/mips/include/asm/errno.h on lines 85 and 98: these basically say there was a network connection reset or time out. Check and see if there are timeouts you can adjust on the remote network program, or send some periodic filler bytes to ensure that the connection stays awake consistently. You may just be victim of an error in the network transit path between the remote client and your local server (this happens to me when my DSL line hiccups).
EDIT: not sure what the downvote is for. The man page for read explicitly says:
Other errors may occur, depending on the object connected to fd.
The error is probably occuring in the select, not in the read: you're not checking errors after the select, you're just proceeding to the read, which will fail if the select returned an error. I'm betting if you check the errno value after the select call you'll see the errors: you don't need to wait for the read to see the errors.
I have a loop that reads from a socket in Lua:
socket = nmap.new_socket()
socket:connect(host, port)
socket:set_timeout(15000)
socket:send(command)
repeat
response,data = socket:receive_buf("\n", true)
output = output..data
until data == nil
Basically, the last line of the data does not contain a "\n" character, so is never read from the socket. But this loop just hangs and never completes. I basically need it to return whenever the "\n" delimeter is not recognised. Does anyone know a way to do this?
Cheers
Updated
to include socket code
Update2
OK I have got around the initial problem of waiting for a "\n" character by using the "receive_bytes" method.
New code:
--socket set as above
repeat
data = nil
response,data = socket:receive_bytes(5000)
output = output..data
until data == nil
return output
This works and I get the large complete block of data back. But I need to reduce the buffer size from 5000 bytes, as this is used in a recursive function and memory usage could get very high. I'm still having problems with my "until" condition however, and if I reduce the buffer size to a size that will require the method to loop, it just hangs after one iteration.
Update3
I have gotten around this problem using string.match and receive_bytes. I take in at least 80 bytes at a time. Then string.match checks to see if the data variable conatins a certain pattern. If so it exits. Its not the cleanest solution, but it works for what I need it to do. Here is the code:
repeat
response,data = socket:receive_bytes(80)
output = output..data
until string.match(data, "pattern")
return output
I believe the only way to deal with this situation in a socket is to set a timeout.
The following link has a little bit of info, but it's on http socket: lua http socket timeout
There is also this one (9.4 - Non-Preemptive Multithreading): http://www.lua.org/pil/9.4.html
And this question: http://lua-list.2524044.n2.nabble.com/luasocket-howto-read-write-Non-blocking-TPC-socket-td5792021.html
A good discussion on Socket can be found on this link:
http://nitoprograms.blogspot.com/2009/04/tcpip-net-sockets-faq.html
It's .NET but the concepts are general.
See update 3. Because the last part of the data is always the same pattern, I can read in a block of bytes and each time check if that block has the pattern. If it has the pattern it will mean that it is the end of the data, append to the output variable and exit.