I'm trying to learn some basic socket programming in python. What i would like to do is have a seperate thread that activliy listens for network activity while my main program does something else.
What I don't understand is why the while(True) loop in the code below never runs. Should it not be on a seperate thread from the socket?
import socket
import multiprocessing
def waitForConnection():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
port = 8000
address = ''
server_socket.bind((address, port))
server_socket.listen(0)
client_socket, client_ip = server_socket.accept()
client_conn = client_socket.makefile(mode='rwb')
process = multiprocessing.Process(target=waitForConnection())
process.start()
#main program
while(True):
print("I never reach this line when no client is connected")
Related
Hi I am trying to create a very simple peer-to-peer chatting program in python. The first user can runs the server.py program below to bind to a socket.
import sys
import socket
import select
import threading
# Bind to socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('127.0.0.1', 11111))
s.listen()
def chat(conn, addr):
# Set blocking to false so that program can send and receive messages at the same time
conn.setblocking(0)
# Receive messages using select
while conn in select.select([conn], [], [], 0)[0]:
text = conn.recv(4096)
if text:
print("{}: {}".format(addr, text))
else:
return
# get user input and send message
while True:
msg = input(">>>")
conn.send(msg.encode())
if __name__ == '__main__':
## Accept connections and start new thread
(conn, addr) = s.accept()
threading.Thread(target=chat, args=([conn, addr])).start()
Then another user can use netcat to connect to the server and communicate. However, the program is only able to get the user's input and send to the other side. The user from the other side is unable to send messages.
input() blocks, so you are falling through your chat function and entering the input() loop and never checking for receiving again. Receive on the thread and enter the input loop on the main thread. TCP is full duplex so you can send/recv at the same time on two threads without turning off blocking.
I also needed to add a newline to the send() as my netcat was line-buffering.
import socket
import threading
# Bind to socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 11111))
s.listen()
def chat(conn, addr):
while True:
text = conn.recv(4096)
if not text: break
print("{}: {}".format(addr, text))
if __name__ == '__main__':
## Accept connections and start new thread
conn, addr = s.accept()
threading.Thread(target=chat, args=(conn, addr), daemon=True).start()
# get user input and send message
while True:
msg = input(">>>")
conn.sendall(msg.encode() + b'\n')
I have a server which accepts a stream of JSON data from a client socket. The server needs to keep all the connections open forever and process the data that comes from them, but the current version of my code can handle a single connection only because the second while loop never ends once the first connection has been established.
import socket
IP = '127.0.0.1'
PORT = 1235
BUFFER = 10
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((IP, PORT))
server_socket.listen(10)
print(f"Listening for incoming connections # {IP}:{PORT}")
while True:
client_socket, client_address = server_socket.accept()
print(f"Established connection with {client_address}")
while True:
received_message = client_socket.recv(BUFFER).decode('utf-8')
while '}' not in received_message:
received_message += client_socket.recv(BUFFER).decode('utf-8')
print(client_address, received_message)
client_socket.send("Message received".encode('utf-8'))
Was able to solve the problem by implementing threading. Here's the working code if anyone wants to use it.
import socket
from _thread import *
IP = '127.0.0.1'
PORT = 1235
BUFFER = 100
thread_count = 0
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((IP, PORT))
server_socket.listen(10)
def threaded_client(client_socket, address):
while True:
received_message = client_socket.recv(BUFFER).decode('utf-8')
while '}' not in received_message:
received_message += client_socket.recv(BUFFER).decode('utf-8')
print(client_address, received_message)
client_socket.send("Message received.".encode('utf-8'))
while True:
client_socket, client_address = server_socket.accept()
print(f"Established connection with {client_address}")
start_new_thread(threaded_client, (client_socket, client_address))
thread_count += 1
print(thread_count)
The primary problem you're facing is that almost all of python's IO is blocking. That means that the execution of the program stops when you want to read or write to a file, or to a socket in this case. The standard solution is to use threads through the threading-library, but there are many other options.
I'd recommend watching David Beazley's video on concurrency, which covers this topic quite well! It can get a little bit complicated, but that's because it's covering a lot of ground fairly quickly!
I am currently programming a python socket server, which is working fine but with a big issue:
First here is the code
import socket
import threading
class ThreadedServer(object):
def __init__(self, host, port):
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
self.sock.bind((self.host, self.port))
def listen(self):
self.sock.listen(6)
while True:
client, address = self.sock.accept()
client.settimeout(20)
threading.Thread(target=self.listenToClient, args=(client, address)).start()
def listenToClient(self, client, address):
size = 1024
while True:
try:
data = client.recv(size)
if data:
response = data
client.send(response)
print(response)
else:
raise
except:
client.close()
return False
if __name__ == "__main__":
while True:
port_num = input("Port: ")
try:
port_num = int(port_num)
break
except ValueError:
pass
ThreadedServer(ipaddress, port_num).listen()
The point is to have a socket server that can listen to multiple clients at the same time.
While i can connect to this socket with another python program, I am having an issue as soon as the socket.close() command came or the client program exits.
Segmentation fault (core dumped)
I assume the issue lies in the multithreading of the python code, however i am unfortunately not able to identify what i have to change to make it resistant to clients closing the socket or exiting the client program. Many stackoverflow answers are referring to C directly and not to python.
Any idea would be greatly appreciated
UPDATE:
rewriting the listen function to :
def listen(self):
# self.sock.listen(6)
while True:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
self.sock.listen(6)
client, address = self.sock.accept()
client.settimeout(20)
threading.Thread(target=self.listenToClient, args=(client, address)).start()
did not help unfortunately
UPDATE2:
running the process in a single thread works (meaning: i replace the threading.Thread line with just a call to the listenToClient function)
I can then connect with a client script, close the connection and open it again.
I am trying a little client server project to get me into network programming but I seem to have got stuck at the first hurdle. I cant seem to get past getting the first line of data only even if its a new connection.
#!/usr/bin/python
import socket
s = socket.socket()
host = '192.168.0.233' # Test Server
port = 7777
s.bind((host, port))
s.listen(5)
while True:
c, addr = s.accept()
print 'Got connection from', addr
data = c.recv(2048)
print(data)
If I telnet to the host running the server, the connection opens fine and I see on the server Got connection from addr, but I also only see the first line of data when I sent 4 lines of data,
I thought because its in a loop it should now always be looking for data?
I know im doing something wrong but unsure what.
Im using Python 2.6.6
recv needs to be in a loop too, at the moment your code is receiving some data and then waiting for a new connection.
https://docs.python.org/2/library/socket.html#example has an example of socket.recv in a loop.
Try this:
#!/usr/bin/python
import socket
import threading
def listenForClients(sock):
while True:
client, address = sock.accept()
client.settimeout(5)
threading.Thread( target = listenToClient, args = (client,address) ).start()
def listenToClient(client, address):
size = 2048
while True:
try:
data = client.recv(size)
if data:
response = "Got connection"
client.send(response)
else:
raise error('Client disconnected')
except:
client.close()
return False
def main(host, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, port))
sock.listen(5)
listenForClients(sock)
if __name__ == "__main__":
main('192.168.0.233',7777)
Here I use a thread for each client. The problem that you have with having Socket.accept() in the loop is that it blocks meaning that concurrent access won't work and you'll only be able to talk to one client at a time.
Try running it in the background and sending it messages with:
#!/usr/bin/python
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('192.168.0.233',7777))
vwhile True:
data = raw_input("enter a message: ")
sock.send(data)
print sock.recv(2048)
I have two scripts, Server.py and Client.py.
I have two objectives in mind:
To be able to send data again and again to server from client.
To be able to send data from Server to client.
here is my Server.py :
import socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "192.168.1.3"
port = 8000
print (host)
print (port)
serversocket.bind((host, port))
serversocket.listen(5)
print ('server started and listening')
while 1:
(clientsocket, address) = serversocket.accept()
print ("connection found!")
data = clientsocket.recv(1024).decode()
print (data)
r='REceieve'
clientsocket.send(r.encode())
and here is my client :
#! /usr/bin/python3
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host ="192.168.1.3"
port =8000
s.connect((host,port))
def ts(str):
s.send('e'.encode())
data = ''
data = s.recv(1024).decode()
print (data)
while 2:
r = input('enter')
ts(s)
s.close ()
The function works for the first time ('e' goes to the server and I get return message back), but how do I make it happen over and over again (something like a chat application) ?
The problem starts after the first time. The messages don't go after the first time.
what am I doing wrong?
I am new with python, so please be a little elaborate, and if you can, please give the source code of the whole thing.
import socket
from threading import *
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "192.168.1.3"
port = 8000
print (host)
print (port)
serversocket.bind((host, port))
class client(Thread):
def __init__(self, socket, address):
Thread.__init__(self)
self.sock = socket
self.addr = address
self.start()
def run(self):
while 1:
print('Client sent:', self.sock.recv(1024).decode())
self.sock.send(b'Oi you sent something to me')
serversocket.listen(5)
print ('server started and listening')
while 1:
clientsocket, address = serversocket.accept()
client(clientsocket, address)
This is a very VERY simple design for how you could solve it.
First of all, you need to either accept the client (server side) before going into your while 1 loop because in every loop you accept a new client, or you do as i describe, you toss the client into a separate thread which you handle on his own from now on.
client.py
import socket
s = socket.socket()
s.connect(('127.0.0.1',12345))
while True:
str = raw_input("S: ")
s.send(str.encode());
if(str == "Bye" or str == "bye"):
break
print "N:",s.recv(1024).decode()
s.close()
server.py
import socket
s = socket.socket()
port = 12345
s.bind(('', port))
s.listen(5)
c, addr = s.accept()
print "Socket Up and running with a connection from",addr
while True:
rcvdData = c.recv(1024).decode()
print "S:",rcvdData
sendData = raw_input("N: ")
c.send(sendData.encode())
if(sendData == "Bye" or sendData == "bye"):
break
c.close()
This should be the code for a small prototype for the chatting app you wanted.
Run both of them in separate terminals but then just check for the ports.
This piece of code is incorrect.
while 1:
(clientsocket, address) = serversocket.accept()
print ("connection found!")
data = clientsocket.recv(1024).decode()
print (data)
r='REceieve'
clientsocket.send(r.encode())
The call on accept() on the serversocket blocks until there's a client connection. When you first connect to the server from the client, it accepts the connection and receives data. However, when it enters the loop again, it is waiting for another connection and thus blocks as there are no other clients that are trying to connect.
That's the reason the recv works correct only the first time. What you should do is find out how you can handle the communication with a client that has been accepted - maybe by creating a new Thread to handle communication with that client and continue accepting new clients in the loop, handling them in the same way.
Tip: If you want to work on creating your own chat application, you should look at a networking engine like Twisted. It will help you understand the whole concept better too.