Currently, I have a home server in my closet basically doing nothing. It has Ubuntu Server 8.0.4 installed, apache for web development ill be using later, ssh, and python/twisted installed.
Here's the issue:
I created an app to talk to "localhost" port-40, using socket implementation, here is a link of what I did but what I want to develop off of : http://www.raywenderlich.com/3932/how-to-create-a-socket-based-iphone-app-and-server
Now connecting to the localhost is no problem but I want to expand this to work with my server.
I implemented the python protocol onto my server and changed the ip address im accessing in the iOS app. Here's the implementation I have, it's exactly the same as the tutorial except for the port i'm accessing.
from twisted.internet.protocol import Factory, Protocol
from twisted.internet import reactor
class IphoneChat(Protocol):
def connectionMade(self):
self.factory.clients.append(self)
print "clients are ", self.factory.clients
def connectionLost(self, reason):
self.factory.clients.remove(self)
def dataReceived(self, data):
a = data.split(':')
print a
#b = password.split(':')
#print b
if len(a) > 1:
command = a[0]
content = a[1]
#username = a[2]
#password = a[2]
msg = ""
#msg2 = ""
if command == "username":
self.name = data
msg = self.name + " has joined"
#self.name = password
#msg2 = self.name + " this is his password"
#print msg
elif command == "password":
self.name = data
msg = self.name + " this is their password"
elif command == "msg":
msg = self.name + ": " + data
print msg
#msg2 = self.name + ": " + password
#print msg2
for c in self.factory.clients:
c.message(msg)#1, msg2)
def message(self, message):
self.transport.write(message + '\n')
factory = Factory()
factory.protocol = IphoneChat #here1#
factory.clients = []
reactor.listenTCP(40, factory)
print "Iphone Chat server started"
reactor.run()
So the REAL issue is, I cannot connect clients to my server or something..... I'm sorry but I am very new to networking.
Any opinion will help.
If you've not established networking communication to your server from the internet before you'll want to establish that you can do that with simple test cases first, there's a lot that can stop traffic from the internet reaching your program on your server.
Is your server connected to the internet through a router? If so, can you communicate with the server from inside the local network (i.e. use the 192.168.xxx.xxx ip address), using something like netcat or telnet?
If that works you should try from outside the network (i.e. using the other ip address, from whatismyip.net or similar). If you've really no prior experience with networking you may have neglected to set up port forwarding, this is a setting on your router.
There are a lot of tutorials around teaching you how to set up a Ubuntu home server, I suggest learning how to host a (very) simple webpage as a means of learning how to network, this will help a lot with debugging a networked program like the one you're making.
Related
So I have created 2 iOS apps (One sends coordinates, one receives them) and a python server. One of the apps sends GPS coordinates to my python server that is hosted on heroku. The server will then emit the received GPS coordinate to the OTHER iOS client app that will drop an Apple Maps pin on the received coordinate.
The project works perfectly while testing on local host with any specified port. However when I have migrated the server to Heroku I was receiving this error The error occurs because Heroku sets it's own port for you to use, where as my code was specifying which port to use. I have been browsing SO for numerous hours trying to implement other peoples solutions where they use os.environ["PORT"] and so on, however due to my novice Python and Twisted skills I haven't succeeded in getting the iOS apps to properly communicate with the Heroku server on the right port. My code for my server is below: (note: I am using Twisted)
import os
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
class IphoneChat(Protocol):
def connectionMade(self):
#self.transport.write("""connected""")
self.factory.clients.append(self)
print "clients are ", self.factory.clients
def connectionLost(self, reason):
self.factory.clients.remove(self)
def dataReceived(self, data):
#print "data is ", data
a = data.split(':')
if len(a) > 1:
command = a[0]
content = a[1]
msg = ""
if command == "new":
self.name = content
msg = content
elif command == "msg":
msg = self.name + ": " + content
print msg
for c in self.factory.clients:
c.message(msg)
def message(self, message):
self.transport.write(message + '\n')
factory = Factory()
factory.protocol = IphoneChat
factory.clients = []
port = 3000
reactor.listenTCP(port, factory)
print "Iphone Chat server started on port ", port
reactor.run()
Heroku have a section in your settings where you can define environment variables.
I have a similar situation when running Django locally, but a similar fix may help you.
In heroku dashboard, select your app and then click the settings tab.
Then if you click reveal config vars and add the key name ON_HEROKU (or something similar if you prefer) with the value True.
Then in your python:
import os
ON_HEROKU = os.environ.get('ON_HEROKU')
if ON_HEROKU:
# get the heroku port
port = int(os.environ.get('PORT', 17995)) # as per OP comments default is 17995
else:
port = 3000
I'm not 100% sure if get('PORT') would be correct, I'm doing this off the top of my head.
Implementing it into your own code would involve something like:
factory = Factory()
factory.protocol = IphoneChat
factory.clients = []
import os
ON_HEROKU = os.environ.get('ON_HEROKU')
if ON_HEROKU:
# get the heroku port
port = int(os.environ.get("PORT", 17995)) # as per OP comments default is 17995
else:
port = 3000
reactor.listenTCP(port, factory)
print "Iphone Chat server started on port %s" % port
reactor.run()
The answer is the following. The port is set by Heroku in the environment variables, and in this example 17995 is used only locally when the PORT environment variable is absent (on local).
port = int(os.environ.get("PORT", 17995))
app.run(host='0.0.0.0', port=port)
Source: https://blog.heroku.com/python_and_django
I recently wrote a code for a small chat program in Python. Sockets connect fine when I connect them from different terminals on the same system. But the same doesn't seem to happen when I connect them from different computers which are connected over the same Wifi network.
Here's the server code:
#!/usr/bin/env python
print "-"*60
print "WELCOME TO DYNASOCKET"
print "-"*60
import socket, os, sys, select
host = "192.168.1.101"
port = 8888
connlist = []
try:
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print "Socket Successfully Created."
connlist.append(s)
s.bind((host,port))
print "Socket Successfully Binded."
s.listen(10)
print "Socket is Now Listening."
except Exception, e:
print "Error : " + str(e)
sys.exit()
def air(sock,message):
for socket in connlist:
if socket != sock and socket != s:
try:
socket.sendall(message)
except:
connlist.remove(socket)
while 1:
read_sockets,write_sockets,error_sockets = select.select(connlist,[],[])
for sock in read_sockets:
if sock == s:
conn, addr = s.accept()
connlist.append(conn)
print "Connected With " + addr[0] + " : " + str(addr[1])
else:
try:
key = conn.recv(1024)
print "<" + str(addr[1]) + ">" + key
data = raw_input("Server : ")
conn.sendall(data + "\n")
air(sock, "<" + str(sock.getpeername()) + ">" + key)
except:
connlist.remove(sock)
print "Connection Lost With : " + str(addr[1])
conn.close()
s.close()
Here's the client script:
#!/usr/bin/env python
print "-"*60
print "WELCOME TO DYNASOCKET"
print "-"*60
import socket, os, sys
host = "192.168.1.101"
port = 8888
try:
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print "Socket Successfully Created."
s.connect((host,port))
print "Connected With " + host + " : " + str(port)
except socket.error, e:
print "Error : " + str(e)
while 1:
reply = raw_input("Client : ")
s.send(reply)
message = s.recv(1024)
print "Server : " + message
s.close()
When I try to connect The client From a different computer I get this error :
Error : [Errno 10060] A Connection attempt failed because the connected party
did not respond after a period of time, or established connection failed
because connected host has failed to respnd.
Your are binding your server only to the local host, so that connections from other hosts are blocked.
Try:
s.bind(("0.0.0.0",port))
I experienced this problem and it took me a many hours to figure this out and I found that (like many others said #Cld) it is your firewall blocking the connection. How I fixed this:
Try to run the server onto the machine that you trying to connect from.
(For example, if you want to run the server on machine A and connect from machine B, run the server on machine B).
If you are on windows (I am not sure about Mac or Linux) it will popup with with the firewall pop-up, which will allow you to give permission to your program to access your private network.
Simply tick the box that says:
"Private networks, such as my home or work network"
and Press allow access
That's it! You've fixed that particular issue. Now feel free to test the server on that machine or close the server and go back to your main machine, which will host that server and run it. You should see that it is now working.
I hope this has helped you, as it is my first post!
EDIT: I also did what #Daniel did in his post with changing the s.bind to include '0.0.0.0'.
I had this same problem for quite sometime, and creating tcp tunnels with ngrok worked for me. You can check it out here
For simple sockets application on your pc, just expose the port you're using by ngrok tcp <port_number>, bind the server socket to localhost and port exposed, and use the url of the tunnel with the port number at client side (typically looks like 0.tcp.us.ngrok.io and a port number).
You can even make multiple tunnels on the free account (needed in my case) by specifying the --region flag: https://ngrok.com/docs#global-locations
I successfully created a simple chat server using this tutorial of reywenderlich
http://www.raywenderlich.com/3932/
Code:
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
class IphoneChat(Protocol):
def connectionMade(self):
#self.transport.write("""connected""")
self.factory.clients.append(self)
print "clients are ", self.factory.clients
def connectionLost(self, reason):
self.factory.clients.remove(self)
def dataReceived(self, data):
#print "data is ", data
a = data.split(':')
if len(a) > 1:
command = a[0]
content = a[1]
msg = ""
if command == "iam":
self.name = content
msg = self.name + " has joined"
elif command == "msg":
msg = self.name + ": " + content
print msg
for c in self.factory.clients:
c.message(msg)
def message(self, message):
self.transport.write(message + '\n')
factory = Factory()
factory.protocol = IphoneChat
factory.clients = []
reactor.listenTCP(79, factory)
print "Iphone Chat server started"
reactor.run()
Basically the whole tutorial shows a chat implementation where user join a specific chat room and chat with each other real-time. But my client wants a peer-to-peer chat mechanism where the user choose a specific user to chat with so I really don't have any idea to make it to reality. I would really appreciate your help. Thanks
To create a p2p connection you need to create a protocol that would allow one of the sides to know the IP address and a listening port of the other side, and the other side to listen on a specific port.
This can be done by creating a request to the chat server to start a p2p connection. The chat server will then send the other client a message asking for permission and after a positive response which should include the listening port transfer that information to the initiating party along with the IP address of his peer.
At this point the initiating client should create a TCP connection to the other party and from the moment the connection is established you can transfer whatever data you'd like.
A simple way to do that would be to allow ASCII-escaped commands to the chat server, for instance /p2p <NICKNAME> which would tell the server that the client wants to start a p2p connection. The server will then be able to send something like /p2p-request from <NICKNAME> to the requested chatter and he could respond with something like /p2p-accept <port> or /p2p-reject <reason>. If the response was /p2p-accept the server can then return to the originating client with something line /p2p-accepted <IP> <port>.
Along with the /p2p-accept the client will need to create a listening socket:
p2p_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
p2p_socket.bind(('', port))
p2p_socket.listen(1)
p2p_chat, p2p_address = p2p_socket.accpet()
The initiating party will need to connect to this socket:
p2p_chat = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
p2p_chat.connect((ip, port))
And once connection is established send() and recv() can be used to send data between the clients.
This can, of course, be written over Twisted, but I'm not well versed in it so I'd rather stick to the low APIs.
I am following this: http://www.raywenderlich.com/3932/how-to-create-a-socket-based-iphone-app-and-server tutorial.
I got this stuff working nice, and being a total noob at this, i can not for the life of me figure out how to add a Python boolean to the 'chatserver.py' document mentioned in the tutorial, pasted below.
Not only do I want to add one, but also to toggle it from the iPhone app with a button, and then request to know it back from the server.
Like,
a button to toggle boolean (How to send a toggle message) and how to ask the server what the state of the boolean is
Apologies for this very open question.
Here is the current server: (Uber-complicated, wohoo!)
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
class IphoneChat(Protocol):
def connectionMade(self):
#self.transport.write("""connected""")
self.factory.clients.append(self)
print "clients are ", self.factory.clients
def connectionLost(self, reason):
self.factory.clients.remove(self)
def dataReceived(self, data):
#print "data is ", data
a = data.split(':')
if len(a) > 1:
command = a[0]
content = a[1]
msg = ""
if command == "iam":
self.name = content
msg = self.name + " has joined"
elif command == "msg":
msg = self.name + ": " + content
print msg
for c in self.factory.clients:
c.message(msg)
def message(self, message):
self.transport.write(message + '\n')
factory = Factory()
factory.protocol = IphoneChat
factory.clients = []
reactor.listenTCP(80, factory)
print "Iphone Chat server started"
reactor.run()
First, you have to decide whether you're talking about a separate boolean value for each connection, or a shared value for everyone, or something in between (e.g., each user has a separate one, available once they log in with iam).
I'll make it per-connection, which I'll do by storing it in as a Protocol instance attribute. You could make it globally shared by storing it in as a module global, or a Protocol class attribute, etc. If you want something more fancy, you'll want a global/class/etc. mapping of some kind.
def connectionMade(self):
#self.transport.write("""connected""")
self.factory.clients.append(self)
print "clients are ", self.factory.clients
self.boolean_flag = False
def dataReceived(self, data):
...
if command == "iam":
self.name = content
msg = self.name + " has joined"
elif command = "set":
self.boolean_flag = True
msg = self.name + " has set his flag"
elif command = "clear":
self.boolean_flag = False
msg = self.name + " has cleared his flag"
elif command = "get":
self.message("Your flag is {}\n".format(self.boolean_flag))
msg = self.name + " has checked his flag"
...
That's all there is to it.
However, it's worth noting that your code is not going to work at all in the first place.
You've created a generic internet.protocol. This means your dataReceived gets called any time some bytes come in. Those bytes could be half a message, or a message and a half. So, I might send you "iam:abarnert" and then "msg:hello", but you're going to see that as, say, "ia", then "m:abarnertmsg:h", and then "ello".
The worst thing is that when you're testing this all on a single computer, or on certain types of LAN, it actually seems to workâeach send on one side is received as exactly one receive on the other side. But as soon as you put it on the internet, it will fail completely.
This is why Twisted comes with a bunch of slightly-higher-level protocols to do, e.g., newline-separated, or netstrings, or whatever else you want. But if you just use the lowest-level raw internet protocol, you have to handle buffering and delimiting and all those things on your own. Which you don't want to do.
I have the following code (almost an exact copy of the Chat server example listed here:
import twisted.scripts.twistd
from twisted.protocols import basic
from twisted.internet import protocol, reactor
from twisted.application import service, internet
class MyChat(basic.LineReceiver):
def connectionMade(self):
print "Got new client!"
self.factory.clients.append(self)
def connectionLost(self, reason):
print "Lost a client!"
self.factory.clients.remove(self)
def lineReceived(self, line):
print "received", repr(line)
for c in self.factory.clients:
c.message(line)
def message(self, message):
self.transport.write(message + '\n')
factory = protocol.ServerFactory()
factory.protocol = MyChat
factory.clients = []
if __name__ == "__main__":
print "Building reactor...."
reactor.listenTCP(50000, factory)
print "Running ractor...."
reactor.run()
else:
application = service.Application("chatserver")
internet.TCPServer(50000, factory).setServiceParent(application)
The server runs without error, and if I connect to it via Telnet, I can send data and the server prints to the console and relays it to all clients (as is expected). However, if I connect to it via a different tool (a MUD client), it never gets the data.
I have ensured that the client is sending the data (Traced the packets with Wireshark, and they're going across the wire), but the server either never receives it, or is choosing to ignore it for some reason.
I have tried this with two MUD clients, gmud, and JMC. If it is important, I am running Windows 7 x64.
Does anyone have any idea why this could be happening?
Thanks,
Mike
EDIT:
Thanks to the hints provided by Maiku Mori, I tried adding another method that was specified in the Twisted API Docs, dataReceived. Once this was added, the MUD clients worked perfectly, but Telnet is now sending every character as it's own set of data, instead of waiting for the user to press Enter.
Here's a snipped of the new code:
def dataReceived(self, data):
print "Dreceived", repr(data)
for c in self.factory.clients:
c.message(data)
# def lineReceived(self, line):
# print "received", repr(line)
# for c in self.factory.clients:
# c.message(line)
Has anyone experiences this before, and if so, how do you get around it? Ideally, I would like Telnet and MUD clients to work with this application.
Thanks again.
In case anyone stumbles across this question with similar problems, I'm leaving my findings as the accepted answer so that people don't have to hunt the way I did.
I fixed the issue by changing the delimiter value from in my Twisted protocol from "\r\n" (default), to just "\n" (which is what my MUD clients send. This means that in Telnet, when you enter the string:
Hello, World
Your application will receive it as:
Hello, World\r
You may need to do data sanitation on the server side to keep things in order. My final code was as follows:
import twisted.scripts.twistd
from twisted.protocols import basic
from twisted.internet import protocol, reactor
from twisted.application import service, internet
class MyChat(basic.LineReceiver):
def __init__(self):
self.delimiter = "\n"
def connectionMade(self):
print "Got new client!"
self.factory.clients.append(self)
def connectionLost(self, reason):
print "Lost a client!"
self.factory.clients.remove(self)
def lineReceived(self, line):
print "received", repr(line)
for c in self.factory.clients:
c.message(line)
def message(self, message):
self.transport.write(message + '\n')
factory = protocol.ServerFactory()
factory.protocol = MyChat
factory.clients = []
if __name__ == "__main__":
print "Building reactor...."
reactor.listenTCP(50000, factory)
print "Running ractor...."
reactor.run()
else:
application = service.Application("chatserver")
internet.TCPServer(50000, factory).setServiceParent(application)
Thanks for all the help.
Are you sure that the MUD clients send line ending chars after each line? The lineReceived will only be called after line ending char has been sent.
EDIT:
Here I found API docs for LineReceiver. You could play around with dataReceived method to see if you are actually getting any kind of data. If I recall you can use it just like lineReceived.