General Python socket questions with several answers - python

I am trying to use an example for a server, but the client can only send one message and then the server will reply with a number.
Here is the code.
import socket
mySocket = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
mySocket.bind ( ( '', 2000 ) )
mySocket.listen ( 1 )
while True:
channel, details = mySocket.accept()
print 'We have opened a connection with', details
print channel.recv ( 100 )
channel.send ( 'Green-eyed monster.' )
channel.close()
Questions:
Why is it that whenever the client sends a message to the server, it responds with a number?
How can I use sockets over the Internet, not over LAN?
Is there a way for me to have the server move data from client to client using sockets - somewhat like an IM program.
I will most likely host this IM server for my friends on my Mac - will it work between OS's (Mac, PC)
Are there any good libraries to use for this? (I have heard that HTTP is great)
These lines of code are really confusing. How do they work?
print channel.recv ( 100 )
channel.send ( 'Green-eyed monster.' )
Also, when I close the server (using the red X), and reuse the port, it says this:
Traceback (most recent call last):
File "C:\Users\****\Desktop\Python\Sockets\First Server\server.py",
line 3, in <module>
mySocket.bind ( ( '', 2003 ) )
File "C:\Python27\lib\socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
error: [Errno 10048] Only one usage of each socket address
(protocol/network address/port) is normally permitted
Lastly, where are some good tutorials for me to understand this better?
Sorry for asking so many questions in the same post, but when I posted this and this people got mad with me for posting about similar problems in different problems.
Python version: Python 2.7.3

I have done some research (over several hours) and have found some solutions to my issues!
3: Yes, There is a way to have the clients communicate with each other, they just have to use the server! You have to initialize an infinite loop on the server side, which will receive data and send it. This is how I solved the issue:
while True:
#Receiving from client
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
print data
#To come out of the loop
conn.close()
This program is part of a definition called clientthread which initializes all connections with clients. The "Actual" loop carries on the rest of the thread:
while True:
#Wait to accept a connection - blocking call
conn, addr = s.accept()
#display client information (IP address)
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#Start new thread takees 1st argument as a function name to be run, second
#is the tuple of arguments to the function
start_new_thread(clientthread ,(conn,))
4: Yes, it will work between OS's. Sockets are independent of the platform.
6: That line of code is actually quite simple. The line print channel.recv ( 100 ) tells the server to print the user input, up to 100 characters. The next line, channel.send ( 'Green-eyed monster.' ) is simply telling the server to send out a message, Green-eyed monster to the client.
7: That error occurs because you cannot have more than one socket open per port. I would suggest using a line such as s.close() or sys.exit() at the end of your code, to close the port. Or you can simply choose another one!
8: There are some great tutorials out on the internet. One that teaches you the basics of sockets is this. Telnet was really confusing for me, so I discovered that in conjunction with this client one can create a customized client which is in fact much better.
If you have any questions, feel free to comment and I will try to answer.

Related

How to use a Python 3 socket client/server setup over the internet (not locally)?

I am trying to implement a simple chat program that uses sockets to transmit data via a UDP connection. However, I can't figure out how to correctly set it up so that people from outside my local network can access it if I am hosting it on my laptop. I am utilizing port 5000, and have port-forwarded that port on my router for my laptop. The port-forwarding doesn't seem to be the issue; at least the "Port Forward Network Utilities" from portforward.com seems to detect it as properly forwarded. Maybe I am mixing up the IP addresses I need to host from and connect with? The code in question is below:
import socket
import threading
import sys
class Server:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connections = []
def __init__(self):
self.sock.bind(('192.168.1.5', 5000))
self.sock.listen(1)
def handler(self, c, a):
while True:
data = c.recv(1024)
for connection in self.connections:
print(data.decode())
connection.send(data)
if not data:
break
def run(self):
while True:
c, a = self.sock.accept()
cThread = threading.Thread(target=self.handler, args=(c, a))
cThread.daemon = True
cThread.start()
self.connections.append(c)
print(self.connections)
class Client:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
usr_name = ""
def sendMsg(self):
while True:
self.sock.send(bytes(self.usr_name + ": " + input("-> "), 'utf-8'))
def __init__(self, address):
self.sock.connect((address, 5000))
self.usr_name = input("Enter a username: ")
iThread = threading.Thread(target=self.sendMsg)
iThread.daemon = True
iThread.start()
while True:
data = self.sock.recv(1024)
if not data:
break
print(data.decode())
if len(sys.argv) > 1:
client = Client(sys.argv[1])
else:
server = Server()
server.run()
As you can see, I have my current local IP address inputted for hosting the server, while the client asks for an IP to connect to. I'm not sure what to do now for hosting this over the internet, but I have tried every IP combination I can think of and it returns a number of errors.
Thanks in advance.
Edit:
The two main errors I was getting are:
Timeout Error [WinError 10060]
My friend received this when trying to connect from another network
[WinError 10061]
I would receive this when trying to connect using my public IP from the same computer
I'm sorry that I can't be more detailed in my errors and provide a full printout, and I will try to update this if I'm able to replicate them.
Edit:
I was able to rewrite it and get it to work, I don't need anymore help with this.
Thanks.
You're port-forwarding UDP port 5000 to 5000.
But you're opening TCP streams, not UDP. That's what SOCK_STREAM means. If you want UDP, you need to use SOCK_DGRAM.
So, you need to make these two consistent. The only problem is, I'm not sure which one you actually want here.
On the one hand, your code is doing connection-oriented recv, and seems to be assuming reliable transmission, which means you probably want TCP.
On the other hand, your code seems to be assuming that each recv(1024) is going to get exactly one send from the other side, which is only true for UDP; TCP sockets are byte streams, not message streams. When you do a recv(1024), you could easily get just the first 12 bytes of an 80-byte line, which means it could end in the middle of a UTF-8 character, which means decode will throw an exception.
I think you want TCP, but with a framing protocol on top of it. The simplest protocol that would probably make sense here is lines of text. Which is pretty easy to do on your own, but even easier to do with socket.makefile, given that you're dedicating a thread to each connection.

Problems with sockets

I'm trying to set up a small server where when the client logs in gets some messages.
The server code
import socket
#Networking
s = socket.socket()
print("Network successfully created")
port = 3642
s.bind(('',port))
print("Network has been binded to %s" %(port))
s.listen(5)
print("Waiting for connections")
while True:
c, addr = s.accept()
print("Got a connection from",addr)
c.send(bytes("Thank you for connecting to me. Currently we","utf-8"))
c.send(bytes("Working on the server","utf-8"))
c.close()
This is the client code
# Import socket module
import socket
# Create a socket object
s = socket.socket()
# Define the port on which you want to connect
port = 3642
# connect to the server on local computer
s.connect(('MyIp..', port))
# receive data from the server
print(s.recv(1024))
# close the connection
s.close()
Everything works fine such as the connecting and the first message gets printed, however I can't get the second message to get printed. The one that says working on the server. I have just began learning about sockets and barely know anything about them so the solution probably is obvious it's just
I can't seem to figure it out. Thank you for any responses. (I would appreciate thorough responses)
If the two sent buffers happen to not get consolidated into a single buffer in the recv (which can happen based on timing, which OS you're running and other factors), then it makes sense that you would not see the second buffer because you're only making one recv call. If you want to receive everything the server sent, put the recv in a loop until it returns an empty string. (Empty string indicates end-of-file [i.e. socket closed by the other end].) – Gil Hamilton

python socket: winerror 10056

I've read throught this introduction to python sockets:
http://docs.python.org/3.3/howto/sockets.html
This is my server
import socket
serversocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serversocket.bind(("localhost",8000))
serversocket.listen(5)
while True:
(client,addr)=serversocket.accept()
data=serversocket.recv(1024)
print(data.decode("utf-8"))
and this is the client
import socket
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost",8000))
The idea is that the server just prints all the data that was sent from the client. As you can see, I intended to encode the message strings as bytes with utf-8. But I never came that far.
With the server script running, I typed the client lines one by one into an IDLE python shell. After the third line, this error prompted up. Since I'm German, this is a vague translation. The error message will probably sound different if you can reproduce the error
Traceback (most recent call last): File "", line 1, in
s.connect(("localhost",8000)) OSError: [WinError 10056] A connection attempt targeted an already connected socket.
How can I solve this error ? The server is slightly adapted, but the client is the exact code from the tutorial. And the error seens rather strange, after all I want the socket to be already connected - with the server . At first I thought that somehow there were already sockets connected to my server but restarting it and typing the client code again lead to the same result.
You want to receive on the client socket, and close the client socket when the client closes. This will process one client at a time, but note it really needs a message protocol implemented to know it has a complete message to decode:
import socket
serversocket = socket.socket()
serversocket.bind(('',8000))
serversocket.listen(5)
while True:
client,addr = serversocket.accept()
while True:
data = client.recv(1024)
if not data: break
print(data.decode('utf8')) # Note this might not contain a complete UTF-8 character.
client.close()
You don't want to call recv() on the socket you call listen() and accept() on. Use the newly connected client instead.

Simple Python Web Server trouble

I'm trying to write a python web server using the socket library. I've been through several sources and can't figure out why the code I've written doesn't work. Others have run very similar code and claim it works. I'm new to python so I might be missing something simple.
The only way it will work now is I send the data variable back to the client. The browser prints the original GET request. When I try to send an HTTP response, the connection times out.
import socket
##Creates several variables, including the host name, the port to use
##the size of a transmission, and how many requests can be handled at once
host = ''
port = 8080
backlog = 5
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(backlog)
while 1:
client, address = s.accept()
data = client.recv(16)
if data:
client.send('HTTP/1.0 200 OK\r\n')
client.send("Content-Type: text/html\r\n\r\n")
client.send('<html><body><h1>Hello World</body></html>')
client.close()
s.close()
You need to consume the input before responding, and you shouldn't close the socket in your while loop:
Replace client.recv(16) with client.recv(size), to consume the request.
Move your last line, s.close() back one indent, so that it is not in your while loop. At the moment you are closing the connection, then trying to accept from it again, so your server will crash after the first request.
Unless you are doing this as an exercise, you should extend SimpleHTTPServer instead of using sockets directly.
Also, adding this line after your create the socket (before bind) fixes any "Address already in use" errors you might be getting.
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Good luck!

address already in use with multithreaded server in twisted

I'm trying to write a multithreaded server in python using twisted. callInThread(self.task) is to create a new thread to run task() every time a client requests sth from the server. When the client sends requests one by one(all through port 53), everything works but when there are multiple requests at the same time, it says
File "", line 1, in bind
socket.error: [Errno 98] Address already in use
Is there sth wrong with my threads, only one can use the port at a time? If so, how am I supposed to go about with multithreading my server?
Thanks a lot!
class BaseThreadedUDPServer(DatagramProtocol):
def datagramReceived(self, datagram, (host, port)):
print "received %r from %s:%d" % (datagram, host, port)
reactor.callInThread(self.task)
def task(a):
print "waiting on port:", csport
while 1:
## RCV QUERY ##
query, addr = csSocket.recvfrom(csbuf)
## GET ANS ##
ans = socket.gethostbyname(query)
## SEND ANS ##
scSocket.sendto(ans, scaddr)
def main():
print "main"
reactor.listenUDP(53, BaseThreadedUDPServer())
reactor.run()
You don't need threads. This is horribly buggy. Twisted is already calling recv for you: and it is the result of that which is passed to datagramReceived. Don't call it again yourself. You don't need a thread.
However, that probably has nothing to do with your problem. 53 is the default DNS port: the problem you have is that another server, probably a DNS server is already running on that computer. Try changing 53 to some other value.
But I'm not really sure; in the future, please paste a full traceback. That traceback line obviously didn't come from the example that you've pasted, since there's nothing on line 1 except a 'class' statement. Also, since this code is indented wrong and raises a SyntaxError, it's obviously not exactly the same as what you're running.
Assuming you are actually doing something with DNS, Twisted has its own DNS server; you should be using twisted.names rather than implementing your own DNS packet parsing.

Categories

Resources