Kodları inceledim ve çalıştırdım, sonra threading modülünü de ekledim ama client bağlanıp resmi gönderince server resmi kayıt etmesi için cliet’in çıkmasını bekliyor. Yani client bir kez bağlanmış oluyor ve başka mesaj gönderemiyor, mesaj alamıyor.
#server.py
import socket, pickle, threading
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("localhost", 1234))
s.listen(5)
print("server çalışıyor...")
def func(con, d):
loads = pickle.loads(d)
with open("resim.jpg","wb") as f:
f.write(loads[0])
f.close()
con.send(b"resim kaydedildi.")
while True:
con, adr = s.accept()
print(adr,"baglandı...")
datas = b""
while True:
recv = con.recv(4096)
if not recv:
break
datas += recv
threading.Thread(target = func, args = (con, datas)).start()
import socket, pickle
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(("localhost", 1234))
while True:
data2 = input("> ")
data3 = input("> ")
with open("deneme.jpg", "rb") as f:
data1 = f.read()
data = pickle.dumps((data1,data2,data3))
c.send(data)
f.close()
client_data = c.recv(1024)
print(client_data.decode())
SOCK_STREAM adi ustunde bir veri akisi yaratiyor. Bir taraftan yapilan send cagrilari diger taraftaki recv'lere tekabul etmek zorunda degil, garanti edilen tek sey bir taraftan yollanan byte’larin diger taraftan ayni sirayla alinmasi.
Bunun uzerine herhangi bir protokol insa etmek icin akisi parcalara bolmek gerekiyor. Bunun en basit yontemleri:
{1. parcanin sabit uzunlukla ifade edilen boyu}{1. parcanin geri kalani}{2. parcanin sabit uzunlukla ifade edilen boyu}{2. parcanin geri kalani}...
seklinde veri yollayip almak. OOB veri veya spesifik TCP implementasyonlariyla yapilabilecek hack’lere deginmiyorum, onlari kullanmak ve pratikteki network katmanlarindan gecirmek cok daha zor.
Bu arada aşağıdaki kodları inceleyin, @aib’in söylemeye çalıştığı şey, önce göndereceğiniz verinin uzunluğunu gönderin, recv fonksiyonuna yazılacak sayı sabit bir sayı değil de sürekli değişen verinin uzunluğu olsun.
server.py
#!/usr/bin/python3.8
# -*- coding: utf-8 -*-
import os
import socket
import pickle
import threading
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("localhost", 1235))
s.listen(5)
connections = []
def accept():
c, addr = s.accept()
connections.append([c, addr, True])
def receive(c):
if c[2]:
c[2] = False
length = c[0].recv(1024).decode("utf-8")
data = b""
while True:
try:
recv = c[0].recv(int(length))
except ValueError:
return
data += recv
if len(data) == int(length):
break
loads = pickle.loads(data)
name, ext = os.path.splitext(loads[2])
count = len([i for i in os.listdir(".") if i.startswith(name)])
with open(f"{name}{count}{ext}", "wb") as f:
f.write(loads[0])
print(loads[1])
c[2] = True
while True:
t1 = threading.Thread(target=accept, daemon=True)
t1.start()
t1.join(1)
if connections:
for i in connections:
t2 = threading.Thread(
target=lambda: receive(c=i),
daemon=True
)
t2.start()
t2.join(1)
client.py
#!/usr/bin/python3.8
# -*- coding: utf-8 -*-
import time
import socket
import pickle
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(("localhost", 1235))
while True:
path = input("Dosya yolu: ")
with open(path, "rb") as f:
data1 = f.read()
data2 = input("Mesaj: ")
data = pickle.dumps((data1, data2, path))
c.send(str(len(data)).encode("utf-8"))
time.sleep(2)
c.send(data)
Not: Kodları değiştirdim, birden çok kullanıcı, birden çok dosya gönderebilirler.
Peki sunucu karşı tarafa bir bilgilendirme mesajı nasıl gönderir?
bende bu hatayı verdi:
s.send(b"resim kaydedildi...")
OSError: [WinError 10057] Yuva bağlı olmadığından ve (bir veri birimi yuvasında bir sento çağrısı kullanırken) adres sağlanmadığından bir veri gönderme veya alma isteğine izin verilmedi
Mesaj gönderme şekli aynı.
Bende hata vermedi. Siz nasıl değişiklikler yaptınız? Bu arada kodları son dakikalarda değiştirdim, acaba son düzeltilen kodları mı kullandınız yoksa düzeltilmeden önceki kodları mı? Bu arada PORT numarası birinde 1234 diğerinde 1235’miş, onu da düzelttim. Bir daha bakın.