KB=1024total_service=0withopen('access_log','r')asf:logs=f.readlines()forloginlogs:log=log.split()servicebyte=log[9]ifservicebyte.isdigit():total_service+=int(servicebyte)total_service/=KBprint('총 서비스 용량: %dKB'%total_service)
네트워크 통신을 위해 사용되는 프로토콜의 종류에 따라 TCP/UDP/Raw 소켓으로 구분됨
TCP 소켓:
TCP(Transmission Control Protocol)를 활용하는 네트워크 소켓
TCP
연결 지향적 프로토콜
포트 번호를 이용하여 서비스를 식별
데이터의 신뢰성 있는 전송을 보장함
데이터의 순서, 무결성, 신뢰성을 보장함
주로 웹, 메일, 파일 공유와 같이 데이터 누락을 허용하지 않는 서비스에서 사용됨
UDP 소켓:
UDP(User Datagram Protocol)를 활용하는 네트워크 소켓
UDP
비연결 지향적 프로토콜
포트 번호를 이용하여 서비스를 식별
빠른 데이터 전송을 목적으로함
연결 설정 과정 없이 데이터를 전송
데이터의 순서나 무결성은 보장하지 않음
VoIP (Voice over IP)와 같이 속도가 중요한 서비스에서 사용됨
Raw 소켓:
특정한 프로토콜에 대한 전송 계층 포매팅 없이 인터넷 프로토콜 패킷을 직접 주고 받을 수 있는 인터넷 소켓
데이터를 전송할 때 직접 프로토콜 헤더를 만들어 전송하고, 데이터를 수신할 때도 프로토콜 헤더를 포함하여 수신
라우터나 네트워크 장비 등에 주로 활용되며 사용자 공간에서 새로운 전송 계층 프로토콜을 구현하는 데에도 활용됨
2.1 서버
#//file: "echo_server1.py"
importsocketHOST=''PORT=9009defrunServer():withsocket.socket(socket.AF_INET,socket.SOCK_STREAM)assock:sock.bind((HOST,PORT))sock.listen(1)print('클라이언트 연결을 기다리는 중..')conn,addr=sock.accept()withconn:print('[%s]와 연결됨'%addr[0])whileTrue:data=conn.recv(1024)ifnotdata:breakprint('메시지 수신 [%s]'%data.decode())conn.sendall(data)runServer()
2.2 클라이언트
#//file: "echo_client1.py"
importsocketHOST='localhost'PORT=9009withsocket.socket(socket.AF_INET,socket.SOCK_STREAM)assock:sock.connect((HOST,PORT))msg=input('메시지 입력: ')sock.sendall(msg.encode())data=sock.recv(1024)print('에코 서버로부터 받은 데이터 [%s]'%data.decode())
3. 에코 서버 만들기(2)
3.1 서버
#//file: "echo_server2.py"
importsocketserverHOST=''PORT=9009classMyTcpHandler(socketserver.BaseRequestHandler):# 이 클래스는 서버 하나당 단한번 초기화됩니다.
# handle() 메쏘드에 클라이언트 연결 처리를 위한 로직을 구현합니다.
defhandle(self):print('[%s] 연결됨'%self.client_address[0])try:whileTrue:self.data=self.request.recv(1024)ifself.data.decode()=='/quit':print('[%s] 사용자에 의해 중단'%self.client_address[0])returnprint('[%s]'%self.data.decode())self.request.sendall(self.data)exceptExceptionase:print(e)defrunServer():print('+++ 에코 서버를 시작합니다.')print('+++ 에코 서버를 끝내려면 Ctrl-C를 누르세요.')try:server=socketserver.TCPServer((HOST,PORT),MyTcpHandler)server.serve_forever()exceptKeyboardInterrupt:print('--- 에코 서버를 종료합니다.')runServer()
3.2 클라이언트
#//file: "echo_client2.py"
importsocketHOST='localhost'PORT=9009withsocket.socket(socket.AF_INET,socket.SOCK_STREAM)assock:sock.connect((HOST,PORT))whileTrue:msg=input('메시지 입력: ')ifmsg=='/quit':sock.sendall(msg.encode())breaksock.sendall(msg.encode())data=sock.recv(1024)print('에코 서버로부터 받은 데이터 [%s]'%data.decode())print('클라이언트 종료')
4. 파일 전송 프로그램 만들기
4.1 파일 송신 프로그램
#//file: "file_server.py"
importsocketserverfromos.pathimportexistsHOST=''PORT=9009classMyTcpHandler(socketserver.BaseRequestHandler):defhandle(self):data_transferred=0print('[%s] 연결됨'%self.client_address[0])filename=self.request.recv(1024)filename=filename.decode()ifnotexists(filename):returnprint('파일 [%s] 전송 시작...'%filename)withopen(filename,'rb')asf:try:data=f.read(1024)whiledata:data_transferred+=self.request.send(data)data=f.read(1024)exceptExceptionase:print(e)print('전송완료[%s], 전송량[%d]'%(filename,data_transferred))defrunServer():print('+++ 파일 서버를 시작합니다.')print('+++ 파일 서버를 끝내려면 Ctrl-C를 누르세요.')try:server=socketserver.TCPServer((HOST,PORT),MyTcpHandler)server.serve_forever()exceptKeyboardInterrupt:print('--- 파일 서버를 종료합니다.')runServer()
4.2 파일 수신 프로그램
#//file: "file_client.py"
importsocketHOST='localhost'PORT=9009defgetFileFromServer(filename):data_transferred=0withsocket.socket(socket.AF_INET,socket.SOCK_STREAM)assock:sock.connect((HOST,PORT))sock.sendall(filename.encode())data=sock.recv(1024)ifnotdata:print('파일[%s]: 서버에 존재하지 않거나 전송중 오류발생'%filename)returnwithopen('download/'+filename,'wb')asf:try:whiledata:f.write(data)data_transferred+=len(data)data=sock.recv(1024)exceptExceptionase:print(e)print('파일 [%s] 전송종료. 전송량 [%d]'%(filename,data_transferred))filename=input('다운로드 받을 파일이름을 입력하세요: ')getFileFromServer(filename)
5. 채팅 서비스 만들기
5.1 채팅 서버 만들기
#//file: "chat_server.py"
importsocketserverimportthreadingHOST=''PORT=9009lock=threading.Lock()classUserManager:def__init__(self):self.users={}defaddUser(self,username,conn,addr):ifusernameinself.users:conn.send('이미 등록된 사용자입니다.\n'.encode())returnNone# 새로운 사용자를 등록함
lock.acquire()self.users[username]=(conn,addr)lock.release()self.sendMessageToAll('[%s]님이 입장했습니다.'%username)print('+++ 대화 참여자 수 [%d]'%len(self.users))returnusernamedefremoveUser(self,username):ifusernamenotinself.users:returnlock.acquire()delself.users[username]lock.release()self.sendMessageToAll('[%s]님이 퇴장했습니다.'%username)print('--- 대화 참여자 수 [%d]'%len(self.users))defmessageHandler(self,username,msg):ifmsg[0]!='/':self.sendMessageToAll('[%s] %s'%(username,msg))returnifmsg.strip()=='/quit':self.removeUser(username)return-1defsendMessageToAll(self,msg):forconn,addrinself.users.values():conn.send(msg.encode())classMyTcpHandler(socketserver.BaseRequestHandler):userman=UserManager()defhandle(self):print('[%s] 연결됨'%self.client_address[0])try:username=self.registerUsername()msg=self.request.recv(1024)whilemsg:print(msg.decode())ifself.userman.messageHandler(username,msg.decode())==-1:self.request.close()breakmsg=self.request.recv(1024)exceptExceptionase:print(e)print('[%s] 접속종료'%self.client_address[0])self.userman.removeUser(username)defregisterUsername(self):whileTrue:self.request.send('로그인ID:'.encode())username=self.request.recv(1024)username=username.decode().strip()ifself.userman.addUser(username,self.request,self.client_address):returnusernameclassChatingServer(socketserver.ThreadingMixIn,socketserver.TCPServer):passdefrunServer():print('+++ 채팅 서버를 시작합니다.')print('+++ 채텅 서버를 끝내려면 Ctrl-C를 누르세요.')try:server=ChatingServer((HOST,PORT),MyTcpHandler)server.serve_forever()exceptKeyboardInterrupt:print('--- 채팅 서버를 종료합니다.')server.shutdown()server.server_close()runServer()