Python 之網絡編程基礎

套接字(socket)初使用

基于TCP協議的socket

tcp是基于鏈接的,必須先啟動服務端,然后再啟動客戶端去鏈接服務端

server端

import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8898))  # 把地址綁定到套接字
sk.listen()                  # 監聽鏈接
conn,addr = sk.accept()      # 接受客戶端鏈接
ret = conn.recv(1024)        # 接收客戶端信息
print(ret)                   # 打印客戶端信息
conn.send(b'hi')             # 向客戶端發送信息
conn.close()                 # 關閉客戶端套接字
sk.close()                   # 關閉服務器套接字(可選)

client端

import socket
sk = socket.socket()           # 創建客戶套接字
sk.connect(('127.0.0.1',8898)) # 嘗試連接服務器
sk.send(b'hello!')
ret = sk.recv(1024)            # 對話(發送/接收)
print(ret)
sk.close()                     # 關閉客戶套接字

問題:有的同學在重啟服務端時可能會遇到端口已被占用

# 加入一條socket配置,重用ip和端口
import socket
from socket import SOL_SOCKET,SO_REUSEADDR
sk = socket.socket()
sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 就是它,在bind前加
sk.bind(('127.0.0.1',8898))              # 把地址綁定到套接字
sk.listen()             # 監聽鏈接
conn,addr = sk.accept() # 接受客戶端鏈接
ret = conn.recv(1024)   # 接收客戶端信息
print(ret)              # 打印客戶端信息
conn.send(b'hi')        # 向客戶端發送信息
conn.close()            # 關閉客戶端套接字
sk.close()              # 關閉服務器套接字(可選)

基于UDP協議的socket

udp是無鏈接的,啟動服務之后可以直接接受消息,不需要提前建立鏈接

server端

import socket
udp_sk = socket.socket(type=socket.SOCK_DGRAM) # 創建一個服務器的套接字
udp_sk.bind(('127.0.0.1',9000))                # 綁定服務器套接字
msg,addr = udp_sk.recvfrom(1024)
print(msg)
udp_sk.sendto(b'hi',addr)              # 對話(接收與發送)
udp_sk.close()                         # 關閉服務器套接字

client端

import socket
ip_port=('127.0.0.1',9000)
udp_sk=socket.socket(type=socket.SOCK_DGRAM)
udp_sk.sendto(b'hello',ip_port)
back_msg,addr=udp_sk.recvfrom(1024)
print(back_msg.decode('utf-8'),addr)

socket參數的詳解

socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)

參數說明:
family地址系列應為AF_INET(默認值),AF_INET6,AF_UNIX,AF_CAN或AF_RDS。
(AF_UNIX 域實際上是使用本地 socket 文件來通信)
type套接字類型應為SOCK_STREAM(默認值),SOCK_DGRAM,SOCK_RAW或其他SOCK_常量之一。
SOCK_STREAM?是基于TCP的,有保障的(即能保證數據正確傳送到對方)面向連接的SOCKET,多用于資料傳送。
SOCK_DGRAM?是基于UDP的,無保障的面向消息的socket,多用于在網絡上發廣播信息。
proto協議號通常為零,可以省略,或者在地址族為AF_CAN的情況下,協議應為CAN_RAW或CAN_BCM之一。
fileno如果指定了fileno,則其他參數將被忽略,導致帶有指定文件描述符的套接字返回。
與socket.fromfd()不同,fileno將返回相同的套接字,而不是重復的。
這可能有助于使用socket.close()關閉一個獨立的插座。

黏包成因

TCP協議中的數據傳遞

1.tcp協議的拆包機制

當發送端緩沖區的長度大于網卡的MTU時,tcp會將這次發送的數據拆成幾個數據包發送出去。MTU是Maximum Transmission Unit的縮寫。意思是網絡上傳送的最大數據包。MTU的單位是字節。 大部分網絡設備的MTU都是1500。如果本機的MTU比網關的MTU大,大的數據包就會被拆開來傳送,這樣會產生很多數據包碎片,增加丟包率,降低網絡速度。

2.面向流的通信特點和Nagle算法

TCP(transport control protocol,傳輸控制協議)是面向連接的,面向流的,提供高可靠性服務。

收發兩端(客戶端和服務器端)都要有一一成對的socket,因此,發送端為了將多個發往接收端的包,更有效的發到對方,使用了優化方法(Nagle算法),將多次間隔較小且數據量小的數據,合并成一個大的數據塊,然后進行封包。這樣,接收端,就難于分辨出來了,必須提供科學的拆包機制。 即面向流的通信是無消息保護邊界的。

對于空消息:tcp是基于數據流的,于是收發的消息不能為空,這就需要在客戶端和服務端都添加空消息的處理機制,防止程序卡住,而udp是基于數據報的,即便是你輸入的是空內容(直接回車),也可以被發送,udp協議會幫你封裝上消息頭發送過去。

可靠黏包的tcp協議:tcp的協議數據不會丟,沒有收完包,下次接收,會繼續上次繼續接收,己端總是在收到ack時才會清除緩沖區內容。數據是可靠的,但是會粘包。

基于tcp協議特點的黏包現象成因?

發送端可以是一K一K地發送數據,而接收端的應用程序可以兩K兩K地提走數據,當然也有可能一次提走3K或6K數據,或者一次只提走幾個字節的數據。也就是說,應用程序所看到的數據是一個整體,或說是一個流(stream),一條消息有多少字節對應用程序是不可見的,因此TCP協議是面向流的協議,這也是容易出現粘包問題的原因。

而UDP是面向消息的協議,每個UDP段都是一條消息,應用程序必須以消息為單位提取數據,不能一次提取任意字節的數據,這一點和TCP是很不同的。

怎樣定義消息呢?

可以認為對方一次性write/send的數據為一個消息,需要明白的是當對方send一條信息的時候,無論底層怎樣分段分片,TCP協議層會把構成整條消息的數據段排序完成后才呈現在內核緩沖區。例如基于tcp的套接字客戶端往服務端上傳文件,發送時文件內容是按照一段一段的字節流發送的,在接收方看了,根本不知道該文件的字節流從何處開始,在何處結束。此外,發送方引起的粘包是由TCP協議本身造成的,TCP為提高傳輸效率,發送方往往要收集到足夠多的數據后才發送一個TCP段。若連續幾次需要send的數據都很少,通常TCP會根據優化算法把這些數據合成一個TCP段后一次發送出去,這樣接收方就收到了粘包數據。

UDP不會發生黏包

UDP(user datagram protocol,用戶數據報協議)是無連接的,面向消息的,提供高效率服務。

不會使用塊的合并優化算法,, 由于UDP支持的是一對多的模式,所以接收端的skbuff(套接字緩沖區)采用了鏈式結構來記錄每一個到達的UDP包,在每個UDP包中就有了消息頭(消息來源地址,端口等信息),這樣,對于接收端來說,就容易進行區分處理了。 即面向消息的通信是有消息保護邊界的。

對于空消息:tcp是基于數據流的,于是收發的消息不能為空,這就需要在客戶端和服務端都添加空消息的處理機制,防止程序卡住,而udp是基于數據報的,即便是你輸入的是空內容(直接回車),也可以被發送,udp協議會幫你封裝上消息頭發送過去。

不可靠不黏包的udp協議:udp的recvfrom是阻塞的,一個recvfrom(x)必須對唯一一個sendinto(y),收完了x個字節的數據就算完成,若是y;x數據就丟失,這意味著udp根本不會粘包,但是會丟數據,不可靠。

補充說明: 用UDP協議發送時,用sendto函數最大能發送數據的長度為:65535- IP頭(20) – UDP頭(8)=65507字節。用sendto函數發送數據時,如果發送數據長度大于該值,則函數會返回錯誤。(丟棄這個包,不進行發送) 用TCP協議發送時,由于TCP是數據流協議,因此不存在包大小的限制(暫不考慮緩沖區的大小),這是指在用send函數時,數據長度參數不受限制。而實際上,所指定的這段數據并不一定會一次性發送出去,如果這段數據比較長,會被分段發送,如果比較短,可能會等待和下一次數據一起發送。

會發生黏包的兩種情況

情況一 發送方的緩存機制

發送端需要等緩沖區滿才發送出去,造成粘包(發送數據時間間隔很短,數據了很小,會合到一起,產生粘包)

情況二 接收方的緩存機制

接收方不及時接收緩沖區的包,造成多個包接收(客戶端發送了一段數據,服務端只收了一小部分,服務端下次再收的時候還是從緩沖區拿上次遺留的數據,產生粘包)

總結

黏包現象只發生在tcp協議中:

  • 從表面上看,黏包問題主要是因為發送方和接收方的緩存機制、tcp協議面向流通信的特點。
  • 實際上,主要還是因為接收方不知道消息之間的界限,不知道一次性提取多少字節的數據所造成的

黏包的解決方案

解決方案一

事先告訴對方要接受的大小,然后sleep

存在的問題: 程序的運行速度遠快于網絡傳輸速度,所以在發送一段字節前,先用send去發送該字節流長度,這種方式會放大網絡延遲帶來的性能損耗

解決方案進階

我們可以借助一個模塊,這個模塊可以把要發送的數據長度轉換成固定長度的字節。這樣客戶端每次接收消息之前只要先接受這個固定長度字節的內容看一看接下來要接收的信息大小,那么最終接受的數據只要達到這個值就停止,就能剛好不多不少的接收完整的數據了。

struct模塊

該模塊可以把一個類型,如數字,轉成固定長度的bytes

struct.pack('i',1111111111111)
struct.error: 'i' format requires -2147483648 <= number <= 2147483647 # 數太大了,所以報錯

?

import json,struct
#假設通過客戶端上傳1T:1073741824000的文件a.txt#為避免粘包,必須自定制報頭
header={'file_size':1073741824000,'file_name':'/a/b/c/d/e/a.txt','md5':'8f6fbf8347faa4924a76856701edb0f3'} #1T數據,文件路徑和md5值#為了該報頭能傳送,需要序列化并且轉為bytes
head_bytes=bytes(json.dumps(header),encoding='utf-8') #序列化并轉成bytes,用于傳輸#為了讓客戶端知道報頭的長度,用struck將報頭長度這個數字轉成固定長度:4個字節
head_len_bytes=struct.pack('i',len(head_bytes)) #這4個字節里只包含了一個數字,該數字是報頭的長度#客戶端開始發送
conn.send(head_len_bytes) #先發報頭的長度,4個bytes
conn.send(head_bytes) #再發報頭的字節格式
conn.sendall(文件內容) #然后發真實內容的字節格式#服務端開始接收
head_len_bytes=s.recv(4) #先收報頭4個bytes,得到報頭長度的字節格式
x=struct.unpack('i',head_len_bytes)[0] #提取報頭的長度head_bytes=s.recv(x) #按照報頭長度x,收取報頭的bytes格式
header=json.loads(json.dumps(header)) #提取報頭#最后根據報頭的內容提取真實的數據,比如
real_data_len=s.recv(header['file_size'])
s.recv(real_data_len)
#_*_coding:utf-8_*_
#http://www.cnblogs.com/coser/archive/2011/12/17/2291160.html
__author__ = 'Linhaifeng'
import struct
import binascii
import ctypesvalues1 = (1, 'abc'.encode('utf-8'), 2.7)
values2 = ('defg'.encode('utf-8'),101)
s1 = struct.Struct('I3sf')
s2 = struct.Struct('4sI')print(s1.size,s2.size)
prebuffer=ctypes.create_string_buffer(s1.size+s2.size)
print('Before : ',binascii.hexlify(prebuffer))
# t=binascii.hexlify('asdfaf'.encode('utf-8'))
# print(t)s1.pack_into(prebuffer,0,*values1)
s2.pack_into(prebuffer,s1.size,*values2)print('After pack',binascii.hexlify(prebuffer))
print(s1.unpack_from(prebuffer,0))
print(s2.unpack_from(prebuffer,s1.size))s3=struct.Struct('ii')
s3.pack_into(prebuffer,0,123,123)
print('After pack',binascii.hexlify(prebuffer))
print(s3.unpack_from(prebuffer,0))

?使用struct解決黏包

借助struct模塊,我們知道長度數字可以被轉換成一個標準大小的4字節數字。因此可以利用這個特點來預先發送數據長度。

發送時接收時
先發送struct轉換好的數據長度4字節先接受4個字節使用struct轉換成數字來獲取要接收的數據長度
再發送數據再按照長度接收數據
# 服務器端
import socket,struct,json
import subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 就是它,在bind前加phone.bind(('127.0.0.1',8080))
phone.listen(5)while True:conn,addr=phone.accept()while True:cmd=conn.recv(1024)if not cmd:breakprint('cmd: %s' %cmd)res=subprocess.Popen(cmd.decode('utf-8'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)err=res.stderr.read()print(err)if err:back_msg=errelse:back_msg=res.stdout.read()conn.send(struct.pack('i',len(back_msg))) # 先發back_msg的長度conn.sendall(back_msg)                    # 在發真實的內容conn.close()
# 客戶端
# _*_coding:utf-8_*_
import socket,time,structs=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(('127.0.0.1',8080))while True:msg=input('>>: ').strip()if len(msg) == 0:continueif msg == 'quit':breaks.send(msg.encode('utf-8'))l = s.recv(4)x = struct.unpack('i',l)[0]print(type(x),x)r_s=0data=b''while r_s < x:r_d = s.recv(1024)data += r_dr_s += len(r_d)# print(data.decode('utf-8'))print(data.decode('gbk'))   # windows默認gbk編碼

我們還可以把報頭做成字典,字典里包含將要發送的真實數據的詳細信息,然后json序列化,然后用struck將序列化后的數據長度打包成4個字節(4個字節足夠用了)

發送時接收時
先發報頭長度先收報頭長度,用struct取出來
再編碼報頭內容然后發送根據取出的長度收取報頭內容,然后解碼,反序列化
最后發真實內容從反序列化的結果中取出待取數據的詳細信息,然后去取真實的數據內容
# 服務器端
import socket,struct,json
import subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加phone.bind(('127.0.0.1',8080))
phone.listen(5)while True:conn,addr=phone.accept()while True:cmd=conn.recv(1024)if not cmd:breakprint('cmd: %s' %cmd)res=subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)err=res.stderr.read()print(err)if err:back_msg=errelse:back_msg=res.stdout.read()headers={'data_size':len(back_msg)}head_json=json.dumps(headers)head_json_bytes=bytes(head_json,encoding='utf-8')conn.send(struct.pack('i',len(head_json_bytes))) # 先發報頭的長度conn.send(head_json_bytes)                       # 再發報頭conn.sendall(back_msg)                           # 在發真實的內容conn.close()
# 客戶端
from socket import *
import struct,jsonip_port=('127.0.0.1',8080)
client=socket(AF_INET,SOCK_STREAM)
client.connect(ip_port)while True:cmd=input('>>: ')if not cmd:continueclient.send(bytes(cmd,encoding='utf-8'))head=client.recv(4)head_json_len=struct.unpack('i',head)[0]head_json=json.loads(client.recv(head_json_len).decode('utf-8'))data_len=head_json['data_size']recv_size=0recv_data=b''while recv_size < data_len:recv_data+=client.recv(1024)recv_size+=len(recv_data)print(recv_data.decode('utf-8'))#print(recv_data.decode('gbk'))  # windows默認gbk編碼

socket的更多方法介紹

服務端套接字函數
s.bind()     # 綁定(主機,端口號)到套接字
s.listen()   # 開始TCP監聽
s.accept()   # 被動接受TCP客戶的連接,(阻塞式)等待連接的到來客戶端套接字函數
s.connect()     # 主動初始化TCP服務器連接
s.connect_ex()  # connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常公共用途的套接字函數
s.recv()         # 接收TCP數據
s.send()         # 發送TCP數據
s.sendall()      # 發送TCP數據
s.recvfrom()     # 接收UDP數據
s.sendto()       # 發送UDP數據
s.getpeername()  # 連接到當前套接字的遠端的地址
s.getsockname()  # 當前套接字的地址
s.getsockopt()   # 返回指定套接字的參數
s.setsockopt()   # 設置指定套接字的參數
s.close()        # 關閉套接字面向鎖的套接字方法
s.setblocking()   # 設置套接字的阻塞與非阻塞模式
s.settimeout()    # 設置阻塞套接字操作的超時時間
s.gettimeout()    # 得到阻塞套接字操作的超時時間面向文件的套接字的函數
s.fileno()        # 套接字的文件描述符
s.makefile()      # 創建一個與該套接字相關的文件
官方文檔對socket模塊下的socket.send()和socket.sendall()解釋如下:socket.send(string[, flags])
Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Returns the number of bytes sent. Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data.
send()的返回值是發送的字節數量,這個數量值可能小于要發送的string的字節數,也就是說可能無法發送string中所有的數據。如果有錯誤則會拋出異常。socket.sendall(string[, flags])
Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Unlike send(), this method continues to send data from string until either all data has been sent or an error occurs. None is returned on success. On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent.
嘗試發送string的所有數據,成功則返回None,失敗則拋出異常。故,下面兩段代碼是等價的:
# sock.sendall('Hello world\n')
# buffer = 'Hello world\n'
# while buffer:
#     bytes = sock.send(buffer)
#     buffer = buffer[bytes:]

?八.socketserver

# 固定格式,代碼在handle中寫,服務器端
import socketserver
class Myserver(socketserver.BaseRequestHandler):def handle(self):self.data = self.request.recv(1024).strip()print("{} wrote:".format(self.client_address[0]))print(self.data)self.request.sendall(self.data.upper())if __name__ == "__main__":HOST, PORT = "127.0.0.1", 9999# 設置allow_reuse_address允許服務器重用地址socketserver.TCPServer.allow_reuse_address = True# 創建一個server, 將服務地址綁定到127.0.0.1:9999server = socketserver.TCPServer((HOST, PORT),Myserver)# 讓server永遠運行下去,除非強制停止程序server.serve_forever()
# 客戶端
import socketHOST, PORT = "127.0.0.1", 9999
data = "hello"# 創建一個socket鏈接,SOCK_STREAM代表使用TCP協議
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:sock.connect((HOST, PORT))          # 鏈接到客戶端sock.sendall(bytes(data + "\n", "utf-8")) # 向服務端發送數據received = str(sock.recv(1024), "utf-8")# 從服務端接收數據print("Sent:     {}".format(data))
print("Received: {}".format(received))

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/454392.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/454392.shtml
英文地址,請注明出處:http://en.pswp.cn/news/454392.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ajax on ture,細數Ajax請求中的async:false和async:true的差異

實例如下&#xff1a;function test(){var temp"00";$.ajax({async: false,type : "GET",url : userL_checkPhone.do,complete: function(msg){alert(complete);},success : function(data) {alert(success);tempdata;temp"aa";}});alert(temp);…

阿里云郵箱登錄日志中有異地IP登錄是怎么回事?該怎么辦?

注意&#xff0c;請先到阿里云官網 領取幸運券&#xff0c;除了價格上有很多優惠外&#xff0c;還可以參與抽獎。詳見&#xff1a;https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode2a7uv47d&utm_source2a7uv47d以下可能&#xff1a;1、您的郵…

面試之網絡編程和并發

1、簡述 OSI 七層協議。 物理層&#xff1a;主要基于電器特性發送高低電壓(1、0)&#xff0c;設備有集線器、中繼器、雙絞線等&#xff0c;單位&#xff1a;bit 數據鏈路層&#xff1a;定義了電信號的分組方式&#xff0c;設備&#xff1a;交換機、網卡、網橋&#xff0c;單位&…

redis 遠程主機強迫關閉了一個現有的連接_記一次Redis+Getshell經驗分享

你是我患得患失的夢&#xff0c;我是你可有可無的人&#xff0c;畢竟這穿越山河的箭&#xff0c;刺的都是用情之疾的人。前言&#xff1a;當我們接到一個授權滲透測試的時候&#xff0c;常規漏洞如注入、文件上傳等嘗試無果后&#xff0c;掃描端口可能會發現意外收獲。知己知彼…

無線連接 服務器,服務器無線遠程連接

服務器無線遠程連接 內容精選換一換華為云幫助中心&#xff0c;為用戶提供產品簡介、價格說明、購買指南、用戶指南、API參考、最佳實踐、常見問題、視頻幫助等技術文檔&#xff0c;幫助您快速上手使用華為云服務。使用Mac版Microsoft Remote Desktop工具&#xff0c;遠程連接W…

面試前您該做的事情

選自本人作品&#xff1a;《軟件性能測試與LR實戰》 無論您是剛剛畢業的大學生朋友&#xff0c;還是已經有工作經驗的同行&#xff0c;大家都不可避免的面臨一個問題就是找工作或者換工作的問題。在整個應聘過程中&#xff0c;面試無疑是最具有決定性意義的重要環節&#xff0c…

IO模型

IO模型介紹 傳統的網絡IO模型包括五種&#xff1a; blocking IO 阻塞IOnonblocking IO 非阻塞IOIO multiplexing IO多路復用signal driven IO 信號驅動IOasynchronous IO 異步IO 由于signal driven IO&#xff08;信號驅動IO&#xff09;在實際中…

重溫數據結構:樹 及 Java 實現(轉)

轉自&#xff1a;http://blog.csdn.net/u011240877/article/details/53193877 讀完本文你將了解到&#xff1a; 什么是樹樹的相關術語 根節點父親節點孩子節點葉子節點如上所述節點的度樹的度節點的層次樹的高度樹的深度樹的兩種實現 數組表示鏈表表示的節點樹的幾種常見分類及…

Powershell檢測AD賬戶密碼過期時間并郵件通知

腳本主要實現了兩個功能 &#xff1a; 一能判斷賬戶密碼的過期時間并通過郵件通知到賬戶&#xff1b; 二是將這些即將過期的賬戶信息累計通知到管理員。 腳本如下&#xff1a; 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051…

js list刪除指定元素_vue.js

vue.js 中M V MV代表哪一部分 <插值表達式&#xff08;v-cloak v-text v-html v-bind&#xff08;縮寫是:&#xff09; v-on&#xff08;縮寫是&#xff09; v-model v-for v-if v-show &#xff09;<body><div id"app"><!-- 使用 v-cloak 能夠解決…

修改db2管理服務器,創建DB2管理服務器的兩種情況

DB2管理服務器在創建時分為創建一個和創建多個兩種情況&#xff0c;下面就為您詳細介紹這兩種創建DB2管理服務器的情況&#xff0c;供您參考學習。一、創建DB2管理服務器(只能創建一個)1、首先創建管理服務組用戶(可不建)命令&#xff1a;sudo groupadd dasadm12、創建用戶命令…

系統程序員成長計劃-走近專業程序員

轉載時請注明出處和作者聯系方式 文章出處&#xff1a;http://www.limodev.cn/blog 作者聯系方式&#xff1a;李先靜 <xianjimli at hotmail dot com> 需求簡述 用C語言編寫一個雙向鏈表。如果你有一定的C語言編程經驗&#xff0c;這自然是小菜一碟。有的讀者可能連一個…

Python 內置模塊之 asyncio(異步iO)

python3.0&#xff0c;標準庫里的異步網絡模塊&#xff1a;select(非常底層) &#xff0c;第三方異步網絡庫&#xff1a;Tornado&#xff0c;gevent python3.4&#xff0c;asyncio&#xff1a;支持 TCP &#xff0c;子進程 現在的asyncio&#xff0c;有了很多的模塊已經在支持…

前端js文件合并三種方式

最近在思考前端js文件該如何合并&#xff0c;當然不包括不能合并文件&#xff0c;而是我們能合并的文件&#xff0c;想了想應該也只有三種方式。 三個方式如下&#xff1a; 1. 一個大文件&#xff0c;所有js合并成一個大文件&#xff0c;所有頁面都引用它。 2. 各個頁面大文件&…

我們的系統檢測到您的計算機網絡中存在異常流量_如何建立我們的網絡防線?入侵檢測,確保我們的網絡安全...

目前我們的網絡安全趨勢日益嚴峻&#xff0c;那么如何利用入侵檢測系統確保我的網絡安全呢&#xff1f;入侵檢測又是什么呢&#xff1f;網絡安全入侵檢測技術是為保證計算機系統的安全&#xff0c;而設計與配置的一種能夠及時發現并報告系統中未授權或異常現象的技術&#xff0…

sql修改鏈接服務器名稱,SQL Server 創建鏈接服務器的腳本,自定義鏈路服務器的簡短名稱...

USE [master]GO/****** Object: LinkedServer [SQL01] Script Date: 2020/4/9 11:51:17 ******/EXEC master.dbo.sp_addlinkedserver server N‘SQL01‘, srvproductN‘‘, providerN‘SQLNCLI‘, datasrcN‘域名或者IP‘/* For security reasons the linked server remot…

mybatis $和#源代碼分析

JDBC中&#xff0c;主要使用兩種語句&#xff0c;一種是支持參數化和預編譯的PreparedStatement,支持原生sql,支持設置占位符&#xff0c;參數化輸入的參數&#xff0c;防止sql注入攻擊&#xff0c;在mybatis的mapper配置文件中&#xff0c;我們通過使用#和$告訴mybatis我們需要…

git 命令詳解和常見問題解決

功能一 提交&#xff1a;1:git init # 初始化&#xff0c;表示即將對當前文件夾進行版本控制2:git status # 查看Git當前狀態&#xff0c;如&#xff1a;那些文件被修改過、那些文件還未提交到版本庫等。3:git add . # 添加當前目錄下所有文件到版本…

辭職日記----記錄31歲的程序員跳槽心態

vcleaner http://topic.csdn.net/u/20080626/23/8f6a8ecc-c072-43ee-bf2d-7ac2286b6805.html http://topic.csdn.net/u/20080704/23/858fc00d-ec14-4db7-93be-34903b7f157a.html 轉載他的離職日記&#xff0c;有許多東西值得我們認真思考&#xff0c;人活著到底為了什么&a…

從Android源碼的角度分析Binder機制

IPC 為了弄懂IPC的來龍去脈&#xff0c;我將從以下三個方面為大家來講解&#xff0c;希望對大家理解IPC會有幫助 什么是IPC IPC是Inter Process Communication的縮寫&#xff0c;其意思就是進程間的通信&#xff0c;也就是兩個進程之間的通信過程。我們都知道在Android系統中&a…