51

I have two scripts, Server.py and Client.py. I have two objectives in mind:

  1. To be able to send data again and again to server from client.
  2. 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.

toine
  • 1,946
  • 18
  • 24
harveyslash
  • 5,906
  • 12
  • 58
  • 111

4 Answers4

49
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.

Torxed
  • 22,866
  • 14
  • 82
  • 131
  • 1
    Exactly what you asked for, "something like a chat application". This IS a chat application. Your `serversocket.accept()` accepts a socket, delivers it into the class `client()` which is a thread. That thread will run along-side your `accept()` function not blocking other people from connecting while still doing two things. 1) Recieves data from the client. 2) Answers the client upon each message with "Oi you sent something to me". – Torxed Jan 20 '14 at 13:12
  • 1
    @user2670775 Also, you can use your client.py which you already have, this server.py that i "wrote" will work with your client code as well. – Torxed Jan 20 '14 at 13:12
  • error: Exception in thread Thread-1: Traceback (most recent call last): File "C:\Python33\lib\threading.py", line 901, in _bootstrap_inner self.run() File "C:\Users\Harsh's\Desktop\New folder (2)\Sserver.py", line 20, in run print('Client sent:', self.sock.recv(1024).decode()) ConnectionAbortedError: [WinError 10053] An established connection was aborted by the software in your host machine – harveyslash Jan 20 '14 at 13:20
  • You disconnected the client? – Torxed Jan 20 '14 at 13:30
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45647/discussion-between-user2670775-and-torxed) – harveyslash Jan 20 '14 at 13:51
  • @lindhe search for `python b before string` gives https://stackoverflow.com/questions/6269765/what-does-the-b-character-do-in-front-of-a-string-literal. What I tried to convey is that this question was never regarding meaning of python syntax. And there's plenty of questions that are, just not if you grab the first one you find I guess. Also search results vary depending on user. – Torxed Nov 13 '17 at 15:20
  • That search results vary from user to user is also a reason for why I think it was a silly suggestion. "Try finding the answer instead". No worries though. – lindhe Nov 13 '17 at 15:25
15

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.

Mohammad Mahjoub
  • 417
  • 4
  • 12
Nischaya Sharma
  • 431
  • 2
  • 6
  • 16
9

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.

gravetii
  • 9,273
  • 9
  • 56
  • 75
  • so how should I modify it ? do I have to modify client and server ? – harveyslash Jan 20 '14 at 12:04
  • In the while loop you have written, just accept connections for new clients. You typically have to make it multithreaded before you can also read data from the client and send data back. – gravetii Jan 20 '14 at 12:07
  • I am not really making a chat application. I want to receive and send data to and from my raspberryPi. okay,suppose I just want one way transmissionTO the server, then what should I do ? – harveyslash Jan 20 '14 at 12:08
  • If you are looking for just one-way communication, you can write a Thread class in the server that will handle it for that client. The thread will perpetually receive data from the client. So with this design, you are spawning a new thread for each client connection and asking the server to handle all the communication related to that particular client in that thread. – gravetii Jan 20 '14 at 12:16
  • You need to modify just the server if you want to handle only one-way communication – gravetii Jan 20 '14 at 12:25
  • as I said , I am totally new to it. could you give a code snippet ? – harveyslash Jan 20 '14 at 13:02
  • Please look at @Torxed's answer for the code snippet. The server accepts a new connection and creates a new Client object for that client which is basically a thread that will handle communication with it. – gravetii Jan 20 '14 at 13:08
1

I modified @Torxed's answer a little bit and added the usage of a symmetric encryption algorithm (AES) with a secret key that is known only to the client and server. Now it's a little bit more secure :)

Just make sure to create a new secret key using Fernet.generate_key()

Also you might need to install cryptography e.g.: pip install cryptography

Server code:

import socket, ssl
from threading import Thread
from cryptography.fernet import Fernet

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "111.111.111.11" # local ipv4 address, as seen in cmd > ipconfig > ipv4
port = 24836
secret_key = b'58RiNFG-2LEjRqkfVcCv-d5euem2LOxFBp0VaD_ft_M='

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):
        f = Fernet(secret_key)
        while True:
            try:
                message = self.sock.recv(1024)
                if not message:
                    break
                decrypted_message = f.decrypt(message)
                print('Client:', decrypted_message.decode())
                encrypted_response = f.encrypt(b'Message Received.')
                self.sock.send(encrypted_response)
            except ConnectionResetError:
                print(f'Client disconnected')
                break
        self.sock.close()

serversocket.listen(5)
print(f'Server started and listening on {host}:{port}')
while True:
    clientsocket, address = serversocket.accept()
    print(f'New client connected: {address[0]}:{address[1]}')
    client(clientsocket, address)

Client code:

import socket, ssl
from cryptography.fernet import Fernet

clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "111.111.111.11" # servers ip4 address
port = 24836
secret_key = b'58RiNFG-2LEjRqkfVcCv-d5euem2LOxFBp0VaD_ft_M='

clientsocket.connect((host, port))

while True:
    message = input('Client: ')
    f = Fernet(secret_key)
    encrypted_message = f.encrypt(message.encode())
    clientsocket.send(encrypted_message)
    response = clientsocket.recv(1024)
    decrypted_response = f.decrypt(response)
    print('Server:', decrypted_response.decode())
    
clientsocket.close()
Mika C.
  • 70
  • 1
  • 14