I copied the echo server example from the python documentation and it's working fine. But when I edit the code, so it wont send the data back to the client, the socket.recv() method doesn't return when it's called the second time.
import socket
HOST = ''
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(b'ok')
conn.close()
In the original version from the python documentation the while loop is slightly different:
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(data)
Client's code:
import socket
HOST = 'localhost'
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
data = s.recv(1024)
s.close()
print('Received', repr(data))
TCP sockets are streams of data. There is no one-to-one correlation between send calls on one side and receive calls on the other. There is a higher level correlation based on the protocol you implement. In the original code, the rule was that the server would send exactly what it received until the client closed the incoming side of the connection. Then the server closed the socket.
With your change, the rules changed. Now the server keeps receiving and discarding data until the client closes the incoming side of the connection. Then the server sends "ok" and closes the socket.
A client using the first rule hangs because its expecting data before it closes the socket. If it wants to work with this new server rule, it has to close its outgoing side of the socket to tell the server its done, and then it can get the return data.
I've updated the client and server to shutdown parts of the connection and also have the client do multiple recv's in case the incoming data is fragmented. Less complete implementations seem to work for small payloads because you are unlikely to get fragmentation, but break horribly in real production code.
server
import socket
HOST = ''
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(b'ok')
conn.shutdown(socket.SHUT_WR)
conn.close()
client
import socket
HOST = 'localhost'
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
s.shutdown(socket.SHUT_WR)
data = b''
while True:
buf = s.recv(1024)
if not buf:
break
data += buf
s.close()
print('Received', repr(data))
The number of receive and send operations have to match because they are blocking. This is the flow diagram for your code:
Server listen
Client connect
Server receive (this waits until a message arrives at the server) [1]
Client send 'Hello world' (received by [1])
Server receive (because there was data received) [2]
Client receive [3]
Because the server and the client are blocked now, no program can continue any further.
The fix would be to remove the client's receive call because you removed the server's send call.
Related
I'm developing an app and I want to send msgs from the client socket (TCP) to the server socket. I want to send 3 messages, send one, wait till the ACK from the server, send another msg wait till the ACK from the server...
This is my code (client side):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((host,port))
sock.sendall(bytes(INIT_MSG, "UTF-8"))
sock.sendall(bytes(FREQ_MSG, "UTF-8"))
sock.sendall(bytes(KEY_MSG, "UTF-8"))
And in server side:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(("",PORT))
s.listen()
counter = 0
conn, addr = s.accept()
print("Connected by:", addr)
while True:
data = conn.recv(1024)
if not data:
break
But when I use Wireshark to look at the frames, all the data is send in one frame instead of 3. I believe the main problem is in the server side which accepts 1024b.
How can I fix it?
I'm trying to learn about sockets and how to create a server and a client in python.
While reading this great article from Real Python I had difficulties understanding why the server receives two strings, when I only send one.
server.py
import socket
HOST = "127.0.0.1"
PORT = 65432
server = socket.socket(
family=socket.AF_INET,
type=socket.SOCK_STREAM
)
with server:
server.bind((HOST, PORT))
server.listen()
print("Waiting for connections...")
conn, addr = server.accept()
print("Accepted!")
with conn:
print(f"Connected by {addr}")
while True:
data = conn.recv(1024)
print(f"Message received: {data}")
if not data:
print(f"Breaking while loop and closing connection")
break
conn.sendall(data)
client.py
import socket
HOST = "127.0.0.1"
PORT = 65432
client = socket.socket(
family=socket.AF_INET,
type=socket.SOCK_STREAM
)
with client as c:
c.connect((HOST, PORT))
# Get input from client
message = input("Enter your message: ")
c.sendall(str.encode(message))
data = c.recv(1024)
print(f"Received {data}")
Output from server.py after running the server and client:
Waiting for connections...
Accepted!
Connected by ('127.0.0.1', 64476)
Message received: b'message'
Message received: b''
Breaking while loop and close connection
Why does the server receive two messages (b'message' and b'')
The recv() can only empty string when the other end is gone. You are unable to send zero length data over socket (try it :). So the fact you are seeing this is simply because you are not checking for that.
PS: your client's last print() is not correctly indented.
I'm trying to:
Connect to a server/port
Listen for x seconds
Receive user input
Send user input to server
Go back to step 2
So far, I've written the following code, but it's not working properly receiving input after the first send. Any help would be greatly appreciated.
import socket
import select
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('domain.com', 1234))
client_socket.setblocking(0)
timeout = 5
while True:
while True:
ready = select.select([client_socket], [], [], timeout)
if ready[0]:
data = client_socket.recv(4096)
print data
else:
break
data = raw_input("Enter input:")
client_socket.send(data)
You need to have separate server side code and client side code. This article has been referred.
Server binds to a port and listens for clients
server.py
import select
import socket
# Create a TCP/IP socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(0)
# Bind the socket to the port
server_address = ('localhost', 1234)
server.bind(server_address)
# Listen for incoming connections
server.listen(5)
# Sockets from which we expect to read
inputs = [ server ]
# Sockets to which we expect to write
outputs = [ ]
while inputs:
readable, writable, exceptional = select.select(inputs, outputs, inputs)
# Handle inputs
for s in readable:
if s is server:
# A "readable" server socket is ready to accept a connection
connection, client_address = s.accept()
connection.setblocking(0)
inputs.append(connection)
else:
data = s.recv(1024)
if data:
print "Receiving data from client"
print data
else:
inputs.remove(s)
s.close()
Client first establishes a connection with the server and then keeps on sending user input to the server.
client.py
import socket
server_address = ('domain.com', 1234)
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(server_address)
while True:
data = raw_input("Enter input:")
sock.send(data)
Open terminal.
Run server in background:
python server.py &
Run client after that:
python client.py
I know that similar questions have been raised but they don't seem to work for me! I have tried serializing the dictionary then converting that to a string then encoding it before I send it over the socket. No success so far!
This is my server code:
#library
import socket
import pickle
#socket initialization
host = "127.0.0.1"
port = 5000
mainAddr = (host, port)
#dict initialization
dataDict = {} #just imagine that dict has content
#create socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP
s.bind((mainAddr))
s.listen(4)
print('program started')
print('listening..')
while True:
try:
conn, addr = s.accept()
print("connection from: "+str(addr))
print("sending message..")
pickle.dumps(dataDict)
print('pickled!')
dataS = str(dataP)
print('stringed!')
dataE = dataS.encode('UTF-8')
print('encoded!')
s.sendto(dataE,addr)
print('data sent!')
except:
pass
s.close()
For the socket initialization, I've tried other types:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #UDP
s = socket.socket()
For the sending part, I've tried these alternatives:
s.send(dataE)
s.send(dataE,addr)
s.sendall(dataE)
s.sendall(dataE,addr)
When I run the program, these get printed out:
program started
listening..
connection from:<insert addr here>
sending message..
pickled!
stringed!
encoded!
Only data sent! is not sent. So I am guessing that it's the sending part that has a problem.
For the client side, here's the code:
#library
import socket
import pickle
#initialization
host = '127.0.0.1'
port = 5000
buffer = 1024
#create socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP
s.connect((host,port))
print('connected!')
#receive dictionary
print('receiving message..')
while True:
data, addr = s.recvfrom(buffer)
print('received!')
dataD = data.decode("UTF-8")
print('decoded!')
dataP = pickle.loads(dataD)
print('unpickled!')
print(str(dataP))
s.close()
In the client terminal, only the following prints:
connected!
receiving message..
On the client side, I've tried changing the order of unpickling and decoding but still, to no avail.
A TCP server socket is not actually used for sending/receiving data; I'm surprised you're not getting an error when calling s.send() or similar on it. Instead, it's a factory for producing individual sockets for each client that connects to the server - conn, in your code. So, conn.sendall() is what you should be using. No address parameter is required, the individual socket already knows who it is talking to. (.send() is unreliable without some extra work on your part; .sendto() is only used with UDP sockets that have not been connected to a particular client.)
I'm trying the following client and server chat program. Although I get an error whenever I try to run the server program, when the client program runs it stays on a blank screen not allowing me to type anything. I've tried running server first and running client first and I get the same results. I can't read the error from the server program because it flashes the error and closes the window. Here is my code:
server:
#server
import socket
import time
HOST = ''
PORT = 8065
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((HOST,PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
data = conn.recv(1024)
if not data: break
conn.sendall(data)
conn.close()
client:
#client
import socket
import time
HOST = "localhost"
PORT = 8065
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((HOST,PORT))
s.sendall('Helloworld')
data = s.recv(1024)
s.close()
print 'Recieved', repr(data)
Im not an expert but I was able to make your examples work by changing the socket from datagram to stream connection, and then encoding message being sent because strings aren't supported (although this might not effect you since I think that change was made in Python 3...I'm not 100% sure).
I believe the main issue is that you're trying to listen() but SOCK_DGRAM (UDP) doesn't support listen(), you just bind and go from there, whereas SOCK_STREAM (TCP) uses connections.
If you're just trying to get the program going, use the below code, unless there is a specific reason you'd like to use SOCK_DGRAM.
The code is below:
client
#client
import socket
import time
HOST = "localhost"
PORT = 8065
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST,PORT))
test = 'Helloworld'
s.sendall(test.encode())
data = s.recv(1024)
s.close()
print 'Recieved', repr(data)
server
#server
import socket
import time
HOST = ''
PORT = 8065
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST,PORT))
s.listen(1)
conn, addr = s.accept()
print ('Connected by', addr)
while 1:
data = conn.recv(1024)
if not data: break
conn.sendall(data)
conn.close()