Using sockets and threading, my clients won't stay connected - python

I have the following code for my server loop:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((host, port))
while True:
server.listen(1)
clientsock, clientAddress = server.accept()
self.total_clients += 1
self.modules['logger'].log("login", "New connection! => " + str(clientAddress))
self.clients[self.total_clients] = (Client(clientAddress, clientsock, self.total_clients, self.modules))
self.clients[self.total_clients].start()
Basically someone connects to the socket, and after that they're placed in that loop on the 2nd to last line (the one which instantiates the Client class). The Client class is as follows:
class Client(threading.Thread):
def __init__(self, addr, clientsocket, thread_id, modules):
threading.Thread.__init__(self)
self.csocket = clientsocket
self.addr = addr
self.thread_id = thread_id
self.modules = modules
return
def run(self):
while True:
data = self.csocket.recv(2048)
if(len(data) > 1):
data = data.decode()
if data == 'bye':
break
self.clientLog("Data received: {" + data + "}")
self.parseCatch(self.modules['parser'].parse(data))
print ("Client ", clientAddress , " disconnected...")
So basically I want the program to work like this: A client connects to the socket. They are then placed into the run() loop in the Client class-thread indefinitely for anything else they send, and the loop responds to certain packets (this is done in the parseCatch() function which I have not included as it is just a simple "if x received send y back").
Anyways, the program isn't functioning like that. As it works now, a client connects to the socket and is placed into the run() loop in the Client class-thread. This is good so far. They then send a certain packet, lets say they send "hi". This is received in 'data' in the run loop in the bottom Client class, and let's say I respond back to hi with self.csocket.send('hi back');. This works fine. Their client receives the hi back. However, if they send something back, like bye, it is treated as a brand new client.
So somehow, when this arbitrary client replies to my packet I sent in the Client() thread, they are treated as a brand new connection. So if client sends "hi", server sends "hi back", it is so far so good. However, if a client then responds again and says something like "bye", it is somehow handled by the main server loop in the top block of code, and I get the "New connection! =>" message. I do not want the client to be handled in this loop, I want them to be handled in their own preexisting thread.
For some reason when a client replies with new data they exit their thread. The loop appears to not even be broken, because it never says "Client disconnected".
Please help. Thanks.

Related

Python socket - Messages not always registering on server

In trying to familiarize myself with the socket library, I have a simple server and client setup. Basically I've stumbled through and am able to set up connection and get the server and client to talk to each other. To make it more interactive, I have client.py able to send text through the command line. Everything appears to be working properly (with the exception of the server side tearing down connection properly if client input is blank), if I type a message from the client side, it spits it right back out to me. In this example, I have it set up for the server side to print the text as well. What I noticed was, that the server side doesn't alway 'register' what it being sent from the client. I am trying to figure out why this is the case. For being a test, it doesn't really affect anything, I just can't figure out what is taking place behind the scenes.
EDIT:
Actually, after playing around with it for a bit, it appears every other message is being printed out to the server console. I've still yet to figure out why this is the case
Server side:
#server.py
import socket
ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ss.bind(('127.0.0.1',5000))
ss.listen(5)
while True:
conn, addr = ss.accept()
with conn:
print ('Connected by', addr)
while True:
data = conn.recv(4096)
print (data)
if not data:
print ("nothing received from client")
ss.close()
break
Client side:
#client.py
import socket
server = 'localhost'
port = 5000
s = socket. socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 5000))
s.send(bytes(b'Client has connected'))
while True:
msg = input()
s.send(bytes(input(msg),'utf-8'))
if not msg:
print ("Server should tear down connection...")
# s.close()
break
In sockets you there are no methods __exit__ implemented, so you can't use the with conn:
you need to remove this part of code.

Python efficient socket communication

i recently started making a pure skype resolver and after doing everything fine i stuck on the socket communication.
Let me explain
I'm using python to get the user's IP and then the script opens a socket server and it sends the username to an other program written in .NET
Why is that? Well, the python skype API is not that powerfull so i'm using the axSkype library in order to gather more info.
The problem
The python socket sends the username as it should but i dont know the most efficient way to get the info back. I was thinking opening a socket server in the same script and wait for what the .NET program sends back.
I dont really kwon how to make this as fast as possible so i'm asking for your help.
The code
class api:
def GET(self, username):
skypeapi.activateSkype(username)
time.sleep(1) # because skype is ew
buf = []
print("==========================")
print("Resolving user " + username)
#This is where i'm starting the socket and sending data
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 5756))
s.sendall(username)
s.close()
#at this poaint i want to get data back from the .NET app
for logfile in glob.glob('*.log'):
buf += logparse.search(logfile, username)
print("Done!")
print("==========================")
return json.dumps(buf)
class index:
def GET(self):
return render.index()
if __name__ == "__main__":
app.run()
You can bind your socket to the connection. This way, your socket stream will remain open and you will be able to send and receive information easily. Integrate this with the _thread module and you will be able to handle multiple streams. Here is some example code that binds a socket to a stream and just sends back whatever the clients sends it(Although in your case you could send whatever data is necessary)
import socket
from _thread import *
#clientHandle function will just receive and send stuff back to a specific client.
def clientHandle(stream):
stream.send(str.encode("Enter some stuff: "))
while True:
#Here is where the program waits for a response. The 4000 is a buffer limit.
data = stream.recv(4000)
if not data:
#If there is not data, exit the loop.
break
stream.senddall(str.encode(data + "\n"))
#Creating socket.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "" #In this case the host is the localhost but you can put your host
port = 80
try:
#Here the program tries to bind the socket to the stream.
s.bind((host, port))
except socket.error as e:
print("There was an error: " + str(e))
#Main program loop. Uses multithreading to handle multiple clients.
while True:
conn, addr = s.accept()
print("Connected to: " + addr[0] + ": " + str(addr[1]))
start_new_thread(clientHandle,(conn,))
Now in your case, you can integrate this into your api class(Is that where you want to integrate it? Correct me if I'm wrong.). So now when you define and bind your socket, use this code:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
Where, in your case, host is 127.0.0.1, in other words, your localhost, which can also be accessed by socket.gethostbyname(socket.gethostname())(but that's a bit verbose), and then port, which for you is 5756. Once you have bounded your socket, you have to accept connections through the following syntax:
conn, addr = s.accept()
Which then you can pass conn and addr to whatever function or just use in any other code.
Regardless of what you use it in, to receive data you can use socket.recv() and pass it a buffer limit. (Remember to decode whatever you receive.) And of course, you send data by using socket.sendall().
If you combine this with the _thread module, as shown above, you can handle multiple api requests, which could come handy in the future.
Hope this helps.

s.sendall doesn't work inside a thread in python

I'm trying to develop a chat program in python. I want it to have multiple clients so I'm using threading to handle this. However when I try to send the message to all connected clients, the server only sends it to the client which sent the message. I'm not sure if I'm just missing something obvious but here is the code for the server:
import socket
from thread import *
host = '192.168.0.13'
port = 1024
users = int(input("enter number of users: "))
def clienthandler(conn):
while True:
data = conn.recv(1024)
if not data:
break
print data
conn.sendall(data)
conn.close()
serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.bind((host, port))
serversock.listen(users)
for i in range(users):
conn, addr= serversock.accept()
print 'Connected by', addr
start_new_thread(clienthandler, (conn,))
And here is the code for the client:
import socket
host = '192.168.0.13'
port = 1024
usrname = raw_input("enter a username: ")
usrname = usrname + ": "
clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsock.connect((host, port))
while True:
x = raw_input('You: ')
x = usrname + x
clientsock.sendall(x)
data = clientsock.recv(1024)
print data
The "all" in sendall means that it sends all of the data you asked it to send. It doesn't mean it sends it on more than one connection. Such an interface would be totally impractical. For example, what would happen if another thread was in the middle of sending something else on one of the connections? What would happen if one of the connections had a full queue?
sendall: Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Unlike send(), this method continues to send data from string until either all data has been sent or an error occurs. None is returned on success. On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent. -- 17.2. socket
You can try by pulling up the list of users, and iterating through it, and doing an individual send of the same message, though, unless you are the administrator and want to broadcast a warning, this functionality would be pretty mundane.

chat between server and a client in different computers connected to the same wifi using python sockets

iam facing some problems as i was working to extend a simple chat program over the wifi.
Ive named the two programs running on different systems as client and server thought they don't perform their typical functions.
the message sent by the client is correctly displayed by the server program but once the server sends the message it is not received by the client program.Ive checked the IP and everything is fine. both the client and server codes are also similar the only difference is in who sends the message first(client according to my program) .
I need help with this as soon as possible.
thanks in advance.
this is my client program
from socket import *
import sys
import time
TO_ADDR=('192.168.1.101',8135)
hostname=gethostbyname('0.0.0.0')
LOCAL_ADDR=(hostname,8138)
MSG_LEN=1000
fd=socket(AF_INET, SOCK_DGRAM)
fd.bind(LOCAL_ADDR)
s=('',)
msg=''
def recv():
s=fd.recvfrom(MSG_LEN)
print '\n',s[0]
print '\n'
return s[0]
def send(msg):
fd.connect(('192.168.1.101',8135))
fd.sendto(msg,TO_ADDR)
while msg!='stop' or s!='stop':
print '\n'
msg=raw_input('Enter your message:')
send(msg)
s=recv()
print '\n',s[0]
this is my server program
from socket import *
s=('',)
msg=''
TO_ADDR=('198.168.1.103',8138)
hostname=gethostbyname('0.0.0.0')
LOCAL_ADDR=(hostname,8135)
MSG_LEN=1000
fd=socket(AF_INET,SOCK_DGRAM)
fd.bind(LOCAL_ADDR)
def recv():
s=fd.recvfrom(MSG_LEN)
print '\n',s[0]
print '\n'
return s[0]
def send(msg):
fd.connect(('198.168.1.103',8138))
fd.sendto(msg,TO_ADDR)
fd.close()
while s[0]!='stop' or msg!='stop':
s=recv()
msg=raw_input('Enter your message:')
send(msg)
UDP (you are using SOCK_DGRAM) is a stateless protocol. You cannot therefore "connect" to the client from the server as you are trying to do in your code.
See: UDP Communication
You have to do something like this:
data, addr = fd.recvfrom(1024)
fd.sendto(data, addr)
You could change your recv() function to:
def recv():
data, addr = fd.recvfrom(MSG_LEN)
print '\n',s[0]
print '\n'
return data, addr
And your send() function to:
def send(msg, addr):
fd.sendto(msg, addr)
And the last part of your code to:
while s[0]!='stop' or msg!='stop':
data, addr = recv()
msg = raw_input('Enter your message:')
send(msg, addr)
See:
socket.recvfrom
socket.sendto

Python: Socket Programming: accept() and connect calls

I have been self-learning python since few months now , and finally learning Socket programming. As an text book exercise, I am supposed to design a half-duplex chat system . Below is the code. The first request and response are just fine , but everytime I try sending a second message from client, the server seems to be hanging. The program is TCP based.
I am suspecting that since ss.accept() is being called everytime a new message has to be sent, a new thread is being created but since I have made only 1 call to sc.connect() from client , may be my new connection at the server end is hanging there for infinite time.
As a trail : I called ss.accept() outside the while loop, ie making only 1 connection and listening to data over and over on while loop, the conversations works just fine
Can someone please have a look a the code and help me understand where exactly is the issue.
Since, I am learning, I have not moved to twisted yet. I want to learn all the basics first before I move to frameworks.
!bin/usr/env python
import socket, sys
HOST =''
PORT = 1060
ADDR =(HOST,PORT)
def userinput(sock):
usermessage = input('>')
sock.sendall(str(len(usermessage)))
return usermessage
def server():
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(ADDR)
s.listen(1)
print 'the server is listening at',s.getsockname()
while True:
ss,sockname = s.accept()
#listen to determine the bytes sent by client
msglen = ss.recv(4096)
#accept the complete message
msg = ss.recv(int(msglen))
print 'client:', repr(msg)
servermsg = userinput(ss)
ss.sendall(servermsg)
print " ---------------"
ss.close()
def client():
sc = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sc.connect(ADDR)
while True:
message = userinput(sc)
sc.sendall(message)
replylen = sc.recv(4096)
reply = sc.recv(int(replylen))
print "reply:",reply
print "----------------"
sc.close()
if sys.argv[1:] == ['server']:
server()
elif sys.argv[1:] == ['client']:
client()
else:
print >> sys.stderr,'usage:tcp_2_7.py server|client[host]'
Your trial - accepting once and then receiving multiple messages - is how you should do this. Calling accept is waiting for a new connection - you don't need to do this every time you want to send or receive a message, just as you don't want to call connect every time you want to send or receive.
Think of it this way:
When you connect to a chat server, do you connect, send a message, then disconnect immediately? No - you have a constant open connection which messages are sent through, and the connection is only closed at the end of a chat session.
From the docs on accept:
socket.accept()
Accept a connection. The socket must be bound to an
address and listening for connections. The return value is a pair
(conn, address) where conn is a new socket object usable to send and
receive data on the connection, and address is the address bound to
the socket on the other end of the connection.

Categories