i'm just started to learn Python, and i can't implement a good solution.
I want to write a client/server which allows you to send messages (like: texted, entered, texted, entered) on server until you press Ctrl+C interruption, and this int should close the socket both on server and client.
My very basic and, i suppose, very common client/server example on Python, but as you know - this pair is for single shot, and program is closing.
client.py
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 5005
BUFFERSIZE = 1024
sock = socket.socket()
sock.connect((TCP_IP, TCP_PORT))
msg = input('Enter your text: ')
sock.send(msg.encode())
data = sock.recv(BUFFERSIZE).decode()
sock.close()
print('Recieved data: ',data)
server.py
import socket
import sys
TCP_IP = '127.0.0.1'
TCP_PORT = 5005
BUFFER_SIZE = 1024
sock = socket.socket()
sock.bind((TCP_IP, TCP_PORT))
sock.listen(1)
conn, addr = sock.accept()
print('Connection address:\nIP:',addr[0])
print('Port:',addr[1])
while 1:
data = conn.recv(BUFFER_SIZE)
if not data: break
msg = data.decode()
print('Recieved data: ', msg)
conn.send(data)
conn.close()
Any suggestions?
Add a try...finally to the bottom part like so:
try:
while 1:
data = conn.recv(BUFFER_SIZE)
if not data: break
msg = data.decode()
print('Recieved data: ', msg)
conn.send(data)
finally:
conn.close()
Ctrl+C raises KeyboardInterrupt exception. When it does, the finally will be called, and safely close the socket.
The same can be done to the client in order to close it client-side:
try:
msg = input('Enter your text: ')
sock.send(msg.encode())
data = sock.recv(BUFFERSIZE).decode()
finally:
sock.close()
Related
I need to produce endless socket connections, which can be broke only with 1KeyboardInterupt1 or special word.
When I start both programs in different IDEs, the sender asks to input the message. But only the first message sends to the server and all the others don't.
I need to produce an endless cycle, where all inputs are sent to the server on print.
The server part:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 8888))
s.listen(5)
while True:
try:
client, addr = s.accept()
except KeyboardInterrupt:
s.close()
break
else:
res = client.recv(1024)
print(addr, 'says:', res.decode('utf-8'))
And the client:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 8888))
while True:
com = input('Enter the message: ')
s.send(com.encode())
print('sended')
if com == 'exit':
s.close()
break
I tried to do this on the client:
import socket
while True:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 8888))
com = input('Enter the message: ')
s.send(com.encode())
print('sended')
s.close()
if com == 'exit':
break
But this way needs to create a socket, make connection and close socket every iteration.
Is there the way how to do what I described above with only one socket initialization?
The s.close() must be out of the while loop.
I'm trying to run a client/server script, where the client sends a file to the server and waits for responses until the server sends a stop message.
The problem is: once the connection is established the client starts sending data but until I press CTRL-C the server cannot recreate the file. Only after CTRL-C print "file is fully created" and the file becomes visible, instead, before it's seems to be waiting for something. idk where the problem is. Also tried changing condition on send loop using len(), but doesn't work. Anyone know how to fix it ?
client.py :
import socket # Import socket module
# from threading import Thread
s = socket.socket() # Create a socket object
HOST = "101.xx.x.xxx" # public IP address
PORT = 4243 # Reserve a port for your service.
PDF_PATH = "exam.pdf"
s.connect((HOST, PORT))
def send():
f = open(PDF_PATH, "rb")
while data := f.read(4096):
s.send(data)
f.close()
return
def receive():
while 1:
exercise = s.recv(4096)
if exercise == "stop!":
s.close()
break
f = open(f"{exercise}.txt", "wb")
while data := f.read(4096):
f.write(data)
return
def main():
send()
receive()
if __name__ == "__main__":
main()
server.py :
import socket
from threading import Thread
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
HOST = socket.gethostname()
IP = socket.gethostbyname(HOST)
PORT = 4243
s.bind(('', PORT))
s.listen(5)
def receive_file(conn, i):
f = open(f"exam.pdf", "wb")
while received := conn.recv(4096):
f.write(received)
print("File is fully copied\n")
f.close()
def send_result(conn,i):
while 1:
nbr = str(input("which exercise? "))
if nbr == "stop!":
break
f = open(f"exercise{nbr}.txt", "rb")
conn.send(bytes(f"exercise{nbr}.txt", encoding="utf-8"))
while data := f.read(4096):
conn.send(data)
f.close()
def main():
try:
while 1:
i = 0
conn, addr = s.accept()
print("Got connection from", addr)
# c.send(b"Thank you for connecting")
t = Thread(target=receive_file, args=(conn, i))
t.start()
t.join()
t = Thread(target=send_result, args=(conn, i))
t.start()
t.join()
except KeyboardInterrupt:
print("interrupting \n")
conn.close()
s.close()
if _name_ == '_main_':
main()
conn.recv() in the server won't return '' (no more data) unless the client closes the connection or calls shutdown(SHUT_WR) to indicate sends are complete:
def send():
with open(PDF_PATH, "rb") as f:
while data := f.read(4096):
s.sendall(data)
s.shutdown(socket.SHUT_WR)
An alternative is to design a protocol that sends the length of data before the data so you know when you've received the complete transmission. This would be required if you need to send more than one thing without closing the socket or shutting down sends. You're going to need this to make the receive portion of the server work if you want to send more than one exercise file.
Refer to this answer for an example of sending multiple files over a socket.
When trying to send a file with sockets from one device on my network to another it is throttling the data to 2760 bytes and not receiving the whole file on the server side
Here is the code of my server on my raspberry pi:
import socket
import os
host = "my_ip"
port = "my_port"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen()
def send(mess):
con.send(bytes(mess, "utf-8"))
def receive():
global message
message = con.recv(22000).decode('utf-8')
while True:
try:
con, address = s.accept()
print(f"Connection to {address} made successfully")
receive()
if message == "quit":
break
else:
send("received")
print(len(message))
with open("file.py", 'w', encoding='utf-8')as a:
a.write(message)
os.system("python3 file.py")
except:
pass
And here is the code of my client on another device
with open('file.py', 'r', encoding = 'utf-8')as f:
python_file = f.read()
print(len(python_file))
#returns 20940
import socket
host = "my_ip"
port = my_port
def send(mess):
s.send(bytes(mess, 'utf-8'))
def receive():
message = s.recv(1024).decode('utf-8')
print(message)
while True:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
send_it = input("Send File?[y/n]: ")
if send_it == "y":
try:
s.connect((host, port))
send(python_file)
recieve()
except:
pass
if send_it == "quit":
try:
s.connect((host, port))
send(send_it)
recieve()
except:
pass
else:
pass
When i take off the try loop it doesn't give any errors or reason as to why im only receiving part (2760 bytes) of the file. Also it will randomly(rarely) send more than 2760 bytes or it will sometimes send all the bytes. Its pretty consistently only sending 2760 bytes though.
Maybe you want to use sendall() instead of send(). Basically sendall() guarantees that all data will be sent unless an exception is raised and it's a python feature that is offered by other high level languages as well.
In order to receive all bytes sent, it's a good idea to do that using a loop:
data = bytearray(1)
# loop until there is no more data to receive.
while data:
data = socket.recv(1024) # Receive 1024 bytes at a time.
There is a well explained answer on what the difference between send() and sendall() is in python here.
I have started to make my own TCP server and client. I was able to get the server and the client to connect over my LAN network. But when I try to have another client connect to make a three way connection, it does not work. What will happen is only when the first connected client has terminated the connection between, the server and the client, can the other client connect and start the chat session. I do not understand why this happens. I have tried threading, loops, and everything else I can think of. I would appreciate any advice. I feel like there is just one small thing i am missing and I can not figure out what it is.
Here is my server:
import socket
from threading import Thread
def whatBeip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 0))
local_ip_address = s.getsockname()[0]
print('Current Local ip: ' + str(local_ip_address))
def clietConnect():
conn, addr = s.accept()
print 'Connection address:', addr
i = True
while i == True:
data = conn.recv(BUFFER_SIZE)
if not data:
break
print('IM Recieved: ' + data)
conn.sendall(data) # echo
whatBeip()
TCP_IP = ''
TCP_PORT = 5005
BUFFER_SIZE = 1024
peopleIn = 4
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(peopleIn)
for client in range(peopleIn):
Thread(target=clietConnect()).start()
conn.close()
Here is my client
import socket
TCP_IP = '10.255.255.3'
TCP_PORT = 5005
BUFFER_SIZE = 1024
MESSAGE = "Hello, World!"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
i = True
while i == True:
s.sendall(raw_input('Type IM: '))
data = s.recv(BUFFER_SIZE)
s.close()
This is your main problem: Thread(target=clietConnect()).start() executes the function clientConnect and uses it's return value as the Thread function (which is None, so the Thread does nothing)
Also have a look at:
1) You should wait for all connections to close instead of conn.close() in the end of the server:
threads = list()
for client in range(peopleIn):
t = Thread(target=clietConnect)
t.start()
threads.append(t)
for t in threads: t.join()
and to close the connection when no data is received:
if not data:
conn.close()
return
2) You probably want to use SO_REUSEADDR [ Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems? , Python: Binding Socket: "Address already in use" ]
3) And have a look at asyncio for python
I have written a simple script to send and receive messages using the Python socket module. I want to first send a message using sendMsg and then receive a response using listen. sendMsg works fine but when my server sends a response I receive the error:
"[WinError 10038] An operation was attempted on something that is not a socket"
I close the socket connection in sendMsg and then try to bind it in listen, but it's at this line that the error is produced. Please could someone show me what I am doing wrong!
import socket
port = 3400
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((socket.gethostname(), port))
def sendMsg():
print("\nSending message:\n\n")
msg = ("Sample text").encode("utf-8")
s.send(msg)
s.close()
def listen():
s.bind(("", port))
s.listen(1)
serverSocket, info = s.accept()
print("Connection from", info, "\n")
while 1:
try:
buf = bytearray(4000)
view = memoryview(buf)
bytes = serverSocket.recv_into(view, 4000)
if bytes:
stx = view[0]
Size = view[1:3]
bSize = Size.tobytes()
nTuple = struct.unpack(">H", bSize)
nSize = nTuple[0]
message = view[0:3+nSize]
messageString = message.tobytes().decode("utf-8").strip()
messageString = messageString.replace("\x00", "")
else:
break
except socket.timeout:
print("Socket timeout.")
break
sendMsg()
listen()
Note: I have implemented listen in a separate client and used the line
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 3)
before s.bind() and s.connect(). This works OK. It would be nice to have it all in one client though.
As per the docs the socket.close() will close the socket and no further operations are allowed on it.
So in your code this line s.close() is closing the socket.
Because of that the s.bind(("", port)) will not work as the socket s is already closed!