Python3网络编程——socket编程之Tcp编程

1:Python3中socket编程介绍

这里就不介绍网络编程的基础知识了,比如TCP/IP协议,OSI模型,TCP的三次握手等。下面直接介绍python中socket编程;

2:简单的点对点

只接受单个连接的服务端:

01_TcpServer.py:

<code> 
 

import

socket

import

time server = socket.socket() ip_port = (

'127.0.0.1'

,

8000

) server.bind(ip_port) server.listen(

10

) print(

'启动服务:等待客户端的连接......'

) conn,addr = server.accept() print(

'客户端已连接:'

) print(conn) print(addr)

while

True

: print(

'等待客户端的数据:'

) client_data = conn.recv(

1024

) client_data = client_data.decode(

'utf-8'

) stru_t = time.localtime(float(client_data)) strTime = time.strftime(

'%Y-%m-%d %H:%M:%S'

,stru_t) print(

f'接收来自

{addr}

的数据:

{strTime}

'

) conn.send(str(time.time()).encode(

'utf-8'

)) conn.close() server.close()/<code>

01_TcpClient.py

<code># -*- coding: utf

-8

-*- import socket import

time

client = socket.socket() ip_port = (

'127.0.0.1'

,

8000

) client.connect(ip_port)

while

True: client.send(str(

time

.

time

()).encode(

'utf-8'

))

print

(

'等待服务端的数据:'

) server_data = client.recv(

1024

) server_data = server_data.decode(

'utf-8'

) stru_t =

time

.localtime(float(server_data)) strTime =

time

.strftime(

'%Y-%m-%d %H:%M:%S'

, stru_t)

print

(f

'来自服务端的数据:{strTime}'

)

time

.sleep(

10

) client.

close

()/<code>

3:并发服务端

3.1:创建线程处理

对于每个客户端连接都创建一个线程来处理:

02_TcpServer.py:

<code> 
 

import

socket

from

socket

import

SOL_SOCKET,SO_REUSEADDR

import

time

import

threading

import

traceback

def

handle_client

(conn, addr)

:

print(conn, addr)

while

True

:

try

: print(

f'等待客户端

{addr}

的数据:'

) client_data = conn.recv(

1024

) client_data = client_data.decode(

'utf-8'

) stru_t = time.localtime(float(client_data)) strTime = time.strftime(

'%Y-%m-%d %H:%M:%S'

, stru_t) print(

f'接收来自

{addr}

的数据:

{strTime}

'

) conn.send(str(time.time()).encode(

'utf-8'

))

except

ConnectionResetError: val = traceback.format_exc() print(val)

break

except

Exception: val = traceback.format_exc() print(val) print(

f'关闭链接

{addr}

'

) conn.close()

def

StartTcpServer

(ip,port)

:

server = socket.socket() server.setsockopt(SOL_SOCKET, SO_REUSEADDR,

1

) server.bind((ip,port)) server.listen(

10

)

while

True

:

try

: print(

'等待客户端的连接......'

) conn, addr = server.accept() threading.Thread(target=handle_client, args=(conn, addr)).start()

except

Exception: val = traceback.format_exc() print(val)

break

server.close()

if

__name__ ==

'__main__'

: StartTcpServer(

'127.0.0.1'

,

8000

)/<code>

02_TcpClient.py:

<code> 
 

import

socket

import

time

import

traceback

def

StartTcpClient

(ip_port)

:

client_list = [socket.socket()

for

i

in

range(

3

)]

for

client

in

client_list: print(client) client.connect(ip_port)

while

True

:

for

index,client

in

enumerate(client_list):

try

: client.send(str(time.time()).encode(

'utf-8'

)) print(

f'clirnt[

{index}

],等待服务端的数据:'

) server_data = client.recv(

1024

) server_data = server_data.decode(

'utf-8'

) stru_t = time.localtime(float(server_data)) strTime = time.strftime(

'%Y-%m-%d %H:%M:%S'

, stru_t) print(

f'来自服务端的数据:

{strTime}

'

) time.sleep(

2

)

except

Exception: val = traceback.format_exc() print(val) client.close() client_list.remove(client)

if

__name__ ==

'__main__'

: StartTcpClient((

'127.0.0.1'

,

8000

))/<code>

3.2:socketserver模块处理

在上面使用每来一个连接,就创建一个线程的方式来处理,如果连接的数量过多,创建线程就会出现问题。

在Python中提供了socketserver模块,socketserver在内部使用IO多路复用以及多线程/进程机制,实现了并发处理多个客户端请求的socket服务端。

03_TcpServer.py

<code> 
 

import

socketserver

import

time

import

traceback

def

handle_client_data

(data,addr)

:

try

: data = data.decode(

'utf-8'

) stru_t = time.localtime(int(data)) strTime = time.strftime(

'%Y-%m-%d %H:%M:%S'

, stru_t) print(

f"来自

{addr}

的客户端向你发来信息:

{data}

,转换之后:

{strTime}

"

)

except

Exception:

pass

class

TcpServer

(socketserver.BaseRequestHandler)

:

""" 必须继承socketserver.BaseRequestHandler类 """

def

handle

(self)

:

""" 必须实现这个方法! :return: """

conn = self.request conn.sendall(str(time.time()).encode(

'utf-8'

)) print(

f"1111:

{self.client_address}

"

)

while

True

:

try

: data = conn.recv(

1024

) handle_client_data(data,self.client_address) conn.sendall(str(int(time.time())).encode(

'utf-8'

))

except

Exception: val = traceback.format_exc() print(val)

break

print(

f'退出客户端

{self.client_address}

的处理。'

)

def

StartTcpServer

(ip,port)

:

server = socketserver.ThreadingTCPServer((ip,port), TcpServer) print(

"启动socketserver服务器!"

) server.serve_forever()

if

__name__ ==

'__main__'

: StartTcpServer(

'127.0.0.1'

,

8000

)/<code>

03_TcpClient.py:

<code> 
 
 

import

socket

import

time

import

traceback

def

StartTcpClient

(ip_port,nums)

:

client_list = [socket.socket()

for

i

in

range(nums)]

for

client

in

client_list: print(client) client.connect(ip_port)

while

True

:

try

:

for

index,client

in

enumerate(client_list):

try

: client.sendall(str( int(time.time()) ).encode(

'utf-8'

)) print(

f'clirnt[

{index}

],等待服务端的数据:'

) server_data = client.recv(

1024

)

try

: server_data = server_data.decode(

'utf-8'

) stru_t = time.localtime(float(server_data)) strTime = time.strftime(

'%Y-%m-%d %H:%M:%S'

, stru_t) print(

f'来自服务端的数据:

{server_data}

转换之后:

{strTime}

'

)

except

Exception:

pass

time.sleep(

1

)

except

(ConnectionResetError,ConnectionAbortedError): val = traceback.format_exc() print(val) client.close() client_list.remove(client)

if

len(client_list)

1

:

raise

except

Exception: val = traceback.format_exc() print(val)

except

Exception: val = traceback.format_exc() print(val) print(

'退出'

)

break

def

test

()

:

print(str(time.time() ),time.time(),int(time.time()))

if

__name__ ==

'__main__'

: StartTcpClient((

'127.0.0.1'

,

8000

),

1

) test()/<code>

3.3:使用select模块

Python中的select模块专注于I/O多路复用,提供了select poll epoll三个方法(其中后两个在Linux中可用,windows仅支持select),另外也提供了kqueue方法(freeBSD系统)

select方法:

进程指定内核监听哪些文件描述符(最多监听1024个fd)的哪些事件,当没有文件描述符事件发生时,进程被阻塞;当一个或者多个文件描述符事件发生时,进程被唤醒。

04_TcpServer.py:

<code> 
 

import

socket

import

select

from

socket

import

SOL_SOCKET,SO_REUSEADDR

import

time

import

traceback

def

handle_client_data

(data,addr)

:

try

: data = data.decode(

'utf-8'

) stru_t = time.localtime(int(data)) strTime = time.strftime(

'%Y-%m-%d %H:%M:%S'

, stru_t) print(

f"来自

{addr.getpeername()}

的客户端向你发来信息:

{data}

,转换之后:

{strTime}

"

)

except

Exception:

pass

def

StartTcpServer

(ip,port)

:

server = socket.socket() server.setsockopt(SOL_SOCKET, SO_REUSEADDR,

1

) server.bind((ip,port)) server.listen(

10

) read_fd_list = [server,]

while

True

:

try

: r_list, w_list, error_list = select.select(read_fd_list, [], [],

1

) stru_t = time.localtime(time.time()) strTime = time.strftime(

'%Y-%m-%d %H:%M:%S'

, stru_t) print(

f'select之后:len(r_list)=

{len(r_list)}

,时间:

{strTime}

'

)

for

fd

in

r_list:

if

fd == server: conn, addr = fd.accept() print(addr) read_fd_list.append(conn) data = conn.recv(

1024

) print(

f'接收数据:msg=

{data}

'

) handle_client_data(data, conn) conn.sendall(str(time.time()).encode(

'utf-8'

))

else

:

try

: data = fd.recv(

1024

) handle_client_data(data,fd) fd.sendall(str(int(time.time())).encode(

'utf-8'

))

except

(ConnectionResetError,ConnectionAbortedError,ConnectionRefusedError): val = traceback.format_exc() print(val) fd.close() read_fd_list.remove(fd)

except

Exception: val = traceback.format_exc() print(val)

break

server.close()

if

__name__ ==

'__main__'

: StartTcpServer(

'127.0.0.1'

,

8000

)/<code>

04_TcpClient.py:

<code> 
 

import

socket

import

time

import

traceback

def

StartTcpClient

(ip_port,nums)

:

client_list = [socket.socket()

for

i

in

range(nums)]

for

client

in

client_list: print(client) client.connect(ip_port)

while

True

:

try

:

for

index,client

in

enumerate(client_list):

try

: client.sendall(str( int(time.time()) ).encode(

'utf-8'

)) print(

f'clirnt[

{index}

],等待服务端的数据:'

) server_data = client.recv(

1024

) server_data = server_data.decode(

'utf-8'

) stru_t = time.localtime(float(server_data)) strTime = time.strftime(

'%Y-%m-%d %H:%M:%S'

, stru_t) print(

f'来自服务端的数据:

{server_data}

转换之后:

{strTime}

'

)

except

(ConnectionResetError, ConnectionAbortedError, ConnectionRefusedError): val = traceback.format_exc() print(val) client.close() client_list.remove(client)

if

len(client_list)

1

:

raise

except

Exception: val = traceback.format_exc() print(val)

except

Exception: val = traceback.format_exc() print(val) print(

'退出'

)

break

if

__name__ ==

'__main__'

: StartTcpClient((

'127.0.0.1'

,

8000

),

1

) /<code>

4:socket实现web服务器

4.1:简单web服务器

在浏览器中访问
http://127.0.0.1:8000/home 等

<code> 

import

socket

def

StartWebServer

(ip,port)

:

sk = socket.socket() sk.bind((ip,port)) sk.listen()

while

True

: conn, addr = sk.accept() data = conn.recv(

8096

) print(data) conn.send(

b'HTTP/1.1 200 OK\r\n\r\n'

)

try

: data = data.decode(

'utf-8'

) url = data.split()[

1

] ret_data = url

if

url ==

"/test"

: ret_data =

"test"

elif

url ==

"/home"

: ret_data =

"home"

elif

url ==

"/index"

: ret_data =

"index"

else

: ret_data =

"404"

conn.send(

f'

{ret_data}

'

.encode(

'utf-8'

))

except

Exception:

pass

conn.close()

if

__name__ ==

'__main__'

: StartWebServer(

'127.0.0.1'

,

8000

)/<code>

4.2:简单web服务器:函数版本

<code> 

import

socket

import

time

def

test

(url)

:

ret =

f'test:

{url}

'

return

ret.encode(

'utf-8'

)

def

index

(url)

:

ret =

f'index:

{url}

'

return

ret.encode(

'utf-8'

)

def

home

(url)

:

ret =

f'home:

{url}

'

return

ret.encode(

'utf-8'

)

def

gettime

(url)

:

now = time.strftime(

'%Y-%m-%d %H:%M:%S'

) ret =

f'time:

{url}

{now}

'

return

ret.encode(

'utf-8'

) url_map = {

'/test'

:test,

'/index'

:index,

'/home'

:home,

'/time'

:gettime}

def

handle_client_data

(data)

:

data = data.decode(

'utf-8'

) url = data.split()[

1

] ret_data = url

if

url

in

url_map: func = url_map[url] ret_data = func(url)

else

: ret_data =

b"404"

return

ret_data

def

StartWebServer

(ip,port)

:

sk = socket.socket() sk.bind((ip,port)) sk.listen()

while

True

: conn, addr = sk.accept() data = conn.recv(

8096

) print(data) conn.send(

b'HTTP/1.1 200 OK\r\n\r\n'

)

try

: ret_data = handle_client_data(data) conn.send(ret_data)

except

Exception:

pass

conn.close()

if

__name__ ==

'__main__'

: StartWebServer(

'127.0.0.1'

,

8000

)/<code>

在浏览器中访问:
http://127.0.0.1:8000/time

4.3:简单web服务器:返回动态页面

<code> 

import

socket

import

time

def

test

(url)

:

ret =

f'test:

{url}

'

return

ret.encode(

'utf-8'

)

def

index

(url)

:

with

open(

'index.html'

,

'rb'

)

as

f: ret = f.read()

return

ret

def

home

(url)

:

ret =

f'home:

{url}

'

return

ret.encode(

'utf-8'

)

def

gettime

(url)

:

now = time.strftime(

'%Y-%m-%d %H:%M:%S'

)

with

open(

'time.html'

,

'r'

, encoding=

'utf-8'

)

as

f: data = f.read() data = data.replace(

'##time##'

, now)

return

data.encode(

'utf-8'

) url_map = {

'/test'

:test,

'/index'

:index,

'/home'

:home,

'/time'

:gettime}

def

handle_client_data

(data)

:

data = data.decode(

'utf-8'

) url = data.split()[

1

] ret_data = url

if

url

in

url_map: func = url_map[url] ret_data = func(url)

else

: ret_data =

b"404"

return

ret_data

def

StartWebServer

(ip,port)

:

sk = socket.socket() sk.bind((ip,port)) sk.listen()

while

True

: conn, addr = sk.accept() data = conn.recv(

8096

) print(data) conn.send(

b'HTTP/1.1 200 OK\r\n\r\n'

)

try

: ret_data = handle_client_data(data) conn.send(ret_data)

except

Exception:

pass

conn.close()

if

__name__ ==

'__main__'

: StartWebServer(

'127.0.0.1'

,

8000

)/<code>

index.html

<code> >

<

html

lang

=

"en"

>

<

head

>

<

meta

charset

=

"UTF-8"

>

<

title

>

index

title

>

head

>

<

body

>

<

div

>

<

h1

>

index

h1

>

<

h2

>

index

h2

>

<

h3

>

index

h3

>

<

h4

>

index

h4

>

div

>

body

>

html

>

/<code>

time.html

<code> >

<

html

lang

=

"en"

>

<

head

>

<

meta

charset

=

"UTF-8"

>

<

title

>

time

title

>

head

>

<

body

>

<

h1

>

当前时间是: ##time##

h1

>

body

>

html

>

/<code>

4.4:并发web服务器

使用socketserver实现:

<code> 
 

import

socketserver

import

time

import

traceback

def

test

(url)

:

ret =

f'test:

{url}

'

return

ret.encode(

'utf-8'

)

def

index

(url)

:

with

open(

'index.html'

,

'rb'

)

as

f: ret = f.read()

return

ret

def

home

(url)

:

ret =

f'home:

{url}

'

return

ret.encode(

'utf-8'

)

def

gettime

(url)

:

now = time.strftime(

'%Y-%m-%d %H:%M:%S'

)

with

open(

'time.html'

,

'r'

, encoding=

'utf-8'

)

as

f: data = f.read() data = data.replace(

'##time##'

, now)

return

data.encode(

'utf-8'

) url_map = {

'/test'

:test,

'/index'

:index,

'/home'

:home,

'/time'

:gettime}

def

handle_client_data

(data)

:

data = data.decode(

'utf-8'

) url = data.split()[

1

] ret_data = url

if

url

in

url_map: func = url_map[url] ret_data = func(url)

else

: ret_data =

b"404"

return

ret_data

class

TcpServer

(socketserver.BaseRequestHandler)

:

""" 必须继承socketserver.BaseRequestHandler类 """

def

handle

(self)

:

""" 必须实现这个方法! :return: """

conn = self.request

while

True

:

try

: data = conn.recv(

8096

) print(data) conn.send(

b'HTTP/1.1 200 OK\r\n\r\n'

)

try

: ret_data = handle_client_data(data) conn.sendall(ret_data)

except

Exception:

pass

break

except

Exception: val = traceback.format_exc() print(val)

break

print(

f'退出客户端

{self.client_address}

的处理。'

)

def

StartTcpServer

(ip,port)

:

server = socketserver.ThreadingTCPServer((ip,port), TcpServer) print(

"启动socketserver服务器!"

) server.serve_forever()

if

__name__ ==

'__main__'

: StartTcpServer(

'127.0.0.1'

,

8000

)/<code>


Python3网络编程——socket编程之Tcp编程


分享到:


相關文章: