Python學習筆記整理總結【網路編程】【線程/進程/協程/IO多路模型/select/poll/epoll/selector】

来源:http://www.cnblogs.com/liwei1153300111/archive/2017/11/26/6931626.html
-Advertisement-
Play Games

一、socket(單鏈接) 1、socket:應用層與TCP/IP協議族通信的中間軟體抽象層,它是一組介面。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket介面後面;也有人將socket說成ip+port,ip是用來標識互聯網中的一臺主機的位置,而por ...


一、socket(單鏈接)

1、socket:應用層與TCP/IP協議族通信的中間軟體抽象層,它是一組介面。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket介面後面;也有人將socket說成ip+port,ip是用來標識互聯網中的一臺主機的位置,而port是用來標識這台機器上的一個應用程式,ip地址是配置到網卡上的,而port是應用程式開啟的,ip與port的綁定就標識了互聯網中獨一無二的一個應用程式;而程式的pid是同一臺機器上不同進程或者線程的標識。

2、套接字:用於在同一臺主機上多個應用程式之間的通訊。套接字有兩種(或者稱為有兩個種族),分別是基於文件型(AF_UNIX)和基於網路型(AF_INET)。

3、基於TCP的套接字(類型一)

工作原理:先從伺服器端說起。伺服器端先初始化Socket,然後與埠綁定(bind),對埠進行監聽(listen),調用accept阻塞,等待客戶端連接。在這時如果有個客戶端初始化一個Socket,然後連接伺服器(connect),如果連接成功,這時客戶端與伺服器端的連接就建立了。客戶端發送數據請求,伺服器端接收請求並處理請求,然後把回應數據發送給客戶端,客戶端讀取數據,最後關閉連接,一次交互結束

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # _author_soloLi
 4 import socket                         #導入socket模塊
 5 ip_port = ("127.0.0.1",9999)          #設置伺服器ip和埠
 6 server = socket.socket()              #創建server實例   //聲明socket類型同時生成socket對象
 7 server.bind(ip_port)                  #套接字綁定ip與埠
 8 server.listen(5)                      #監聽連接//允許5個客戶端排隊
 9 conn,addr = server.accept()           #等待客戶端連接   // 客戶端連接後,返回新的套接字與IP地址
10 client_data = conn.recv(1024)         #接收數據//把接收的數據實例化
11 #client_data = b'hello'
12 conn.sendall(client_data.upper())     #把數據發送到客戶端  //upper() 字母變成大寫
13 conn.close()                          #關閉連接
#TCP_server
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # _author_soloLi
 4 import socket                         #導入socket模塊
 5 ip_port = ("127.0.0.1",9999)          #設置伺服器ip和埠
 6 client = socket.socket()              #創建client實例
 7 client.connect(ip_port)               #設置要連接的ip和埠
 8 info = "hello world"                  #要發送的數據
 9 client.sendall(info.encode("utf-8"))  #發送數據// 把str轉換為bytes類型
10 server_data = client.recv(1024)       #接收數據
11 client.close()                        #關閉連接
#TCP_client
 1 ① server = socket.socket()
 2 套接字格式:socket(family,type[,protocal]) 使用給定的地址族、套接字類型、協議編號(預設為0)來創建套接字。
 3 參數一:地址簇
 4   socket.AF_INET IPv4(預設)
 5   socket.AF_INET6 IPv6
 6   socket.AF_UNIX 只能夠用於單一的Unix系統進程間通信
 7 參數二:類型
 8   socket.SOCK_STREAM  流式socket  ,    for TCP (預設)
 9   socket.SOCK_DGRAM   數據報式socket , for UDP
10   socket.SOCK_RAW        原始套接字,普通的套接字無法處理ICMP、IGMP等網路報文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報文;此外,利用原始套接字,可以通過IP_HDRINCL套接字選項由用戶構造IP頭。
11   socket.SOCK_RDM       是一種可靠的UDP形式,即保證交付數據報但不保證順序。SOCK_RAM用來提供對原始協議的低級訪問,在需要執行某些特殊操作時使用,如發送ICMP報文。SOCK_RAM通常僅限於高級用戶或管理員運行的程式使用。
12   socket.SOCK_SEQPACKET 可靠的連續數據包服務
13 參數三:協議
14   0  (預設)與特定的地址家族相關的協議,如果是 0 ,則系統就會根據地址格式和套接類別,自動選擇一個合適的協議
15 #創建TCP Socket:server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
16 #創建UDP Socket:server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
17 註意點:
18 1)TCP發送數據時,已建立好TCP連接,所以不需要指定地址。UDP是面向無連接的,每次發送要指定是發給誰。
19 2)服務端與客戶端不能直接發送列表,元組,字典。需要字元串化repr(data)
20 ② server.bind(address)
21   將套接字綁定到地址。address地址的格式取決於地址族。在AF_INET下,以元組(host,port)的形式表示地址
22 ③ server.listen(backlog)
23   開始監聽傳入連接。backlog指定在拒絕連接之前,可以掛起的最大連接數量。該值至少為1,大部分應用程式設為5就可以了。backlog等於5,表示內核已經接到了連接請求,但伺服器還沒有調用accept進行處理的連接個數最大為5,這個值不能無限大,因為要在內核中維護連接隊列
24 ④ server.setblocking(bool)
25   是否阻塞(預設True),如果設置False,那麼accept和recv時一旦無數據,則報錯
26 ⑤ conn,addr = server.accept() 
27   接受連接並返回(conn,address),其中conn是新的套接字對象,可以用來接收和發送數據。address是連接客戶端的地址。接收TCP 客戶的連接(阻塞式)等待連接的到來
28 ⑥ client.connect(address)
29   連接到address處的套接字。一般address的格式為元組(hostname,port),如果連接出錯,返回socket.error錯誤。
30 ⑦ client.connect_ex(address)
31   同上,只不過會有返回值,連接成功時返回 0 ,連接失敗時候返回編碼,例如:10061
32 ⑧ client.close()
33   關閉套接字
34 ⑨ client.recv(bufsize[,flag])
35   接受套接字的數據。數據以字元串形式返回,bufsize指定最多可以接收的數量。flag提供有關消息的其他信息,通常可以忽略
36 ⑩ client.recvfrom(bufsize[.flag])
37   與recv()類似,但返回值是(data,address)。其中data是包含接收數據的字元串,address是發送數據的套接字地址
38 ⑪ server.send(string[,flag])
39   發送TCP數據;將string中的數據發送到連接的套接字。返回值是要發送的位元組數量,該數量可能小於string的位元組大小。即:可能未將指定內容全部發送
40 ⑫ server.sendall(string[,flag])  
41   完整發送TCP數據;將string中的數據發送到連接的套接字,但在返回之前會嘗試發送所有數據。成功返回None,失敗則拋出異常;內部通過遞歸調用send,將所有內容發送出去
42 ⑬ server.sendto(string[,flag],address)
43   將數據發送到套接字,address是形式為(ipaddr,port)的元組,指定遠程地址。返回值是發送的位元組數。該函數主要用於UDP協議
44 ⑭ sk.settimeout(timeout)
45   設置套接字操作的超時期,timeout是一個浮點數,單位是秒。值為None表示沒有超時期。一般,超時期應該在剛創建套接字時設置,因為它們可能用於連接的操作(如 client 連接最多等待5s )
46 ⑮ sk.getpeername()
47   返回連接套接字的遠程地址。返回值通常是元組(ipaddr,port)
48 ⑯ sk.getsockname()
49   返回套接字自己的地址。通常是一個元組(ipaddr,port)
50 ⑰ sk.fileno()
51 套接字的文件描述符
52 
53 
54 ###服務端套接字函數###
55 s.bind()    #綁定(主機,埠號)到套接字
56 s.listen()  #開始TCP監聽
57 s.accept()  #被動接受TCP客戶的連接,(阻塞式)等待連接的到來
58 
59 ###客戶端套接字函數###
60 s.connect()     #主動初始化TCP伺服器連接
61 s.connect_ex()  #connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常
62 
63 ###公共用途的套接字函數###
64 s.recv()            #接收TCP數據
65 s.send()            #發送TCP數據(send在待發送數據量大於己端緩存區剩餘空間時,數據丟失,不會發完)
66 s.sendall()      #發送完整的TCP數據(本質就是迴圈調用send,sendall在待發送數據量大於己端緩存區剩餘空間時,數據不丟失,迴圈調用send直到發完)
67 s.recvfrom()        #接收UDP數據
68 s.sendto()          #發送UDP數據
69 s.getpeername()     #連接到當前套接字的遠端的地址
70 s.getsockname()     #當前套接字的地址
71 s.getsockopt()      #返回指定套接字的參數
72 s.setsockopt()      #設置指定套接字的參數
73 s.close()           #關閉套接字
74 
75 ###面向鎖的套接字方法###
76 s.setblocking()     #設置套接字的阻塞與非阻塞模式
77 s.settimeout()      #設置阻塞套接字操作的超時時間
78 s.gettimeout()      #得到阻塞套接字操作的超時時間
79 
80 ###面向文件的套接字的函數###
81 s.fileno()          #套接字的文件描述符
82 s.makefile()        #創建一個與該套接字相關的文件
#參數功能解釋

4、基於UDP的套接字(類型二)
udp是無鏈接的,先啟動哪一端都不會報錯且可以同時多個客戶端去跟服務端通信

 1 #UDP server
 2 ss = socket()                      #創建一個伺服器的套接字
 3 ss.bind()                          #綁定伺服器套接字
 4 inf_loop:                          #伺服器無限迴圈
 5     cs = ss.recvfrom()/ss.sendto() # 對話(接收與發送)
 6 ss.close()                         # 關閉伺服器套接字
 7 
 8 
 9 #UDP client
10 cs = socket()                   # 創建客戶套接字
11 comm_loop:                      # 通訊迴圈
12     cs.sendto()/cs.recvfrom()   # 對話(發送/接收)
13 cs.close()                      # 關閉客戶套接字
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # _author_soloLi
 4 import socket
 5 ip_port=('127.0.0.1',9000)
 6 BUFSIZE=1024
 7 udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
 8 udp_server_client.bind(ip_port)
 9 
10 while True:
11     msg,addr=udp_server_client.recvfrom(BUFSIZE)
12     print(msg,addr)
13     udp_server_client.sendto(msg.upper(),addr)
#UDP_server
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # _author_soloLi
 4 import socket
 5 ip_port=('127.0.0.1',9000)
 6 BUFSIZE=1024
 7 udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
 8 
 9 while True:
10     msg=input('>>: ').strip()
11     if not msg:continue
12     udp_server_client.sendto(msg.encode('utf-8'),ip_port)
13     back_msg,addr=udp_server_client.recvfrom(BUFSIZE)
14     print(back_msg.decode('utf-8'),addr)
15 udp_client_socket.close()
#UDP_client

##qq聊天(由於udp無連接,所以可以同時多個客戶端去跟服務端通信)##

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # _author_soloLi
 4 import socket
 5 ip_port=('127.0.0.1',8081)
 6 udp_server_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #買手機
 7 udp_server_sock.bind(ip_port)
 8 
 9 while True:
10     qq_msg,addr=udp_server_sock.recvfrom(1024)
11     print('來自[%s:%s]的一條消息:\033[1;44m%s\033[0m' %(addr[0],addr[1],qq_msg.decode('utf-8')))
12     back_msg=input('回覆消息: ').strip()
13 
14     udp_server_sock.sendto(back_msg.encode('utf-8'),addr)
#UDP_server
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # _author_soloLi
 4 import socket
 5 BUFSIZE=1024
 6 udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
 7 
 8 qq_name_dic={
 9     '狗哥alex':('127.0.0.1',8081),
10     '瞎驢':('127.0.0.1',8081),
11     '一棵樹':('127.0.0.1',8081),
12     '武大郎':('127.0.0.1',8081),
13 }
14 
15 
16 while True:
17     qq_name=input('請選擇聊天對象: ').strip()
18     while True:
19         msg=input('請輸入消息,回車發送: ').strip()
20         if msg == 'quit':break
21         if not msg or not qq_name or qq_name not in qq_name_dic:continue
22         udp_client_socket.sendto(msg.encode('utf-8'),qq_name_dic[qq_name])
23 
24         back_msg,addr=udp_client_socket.recvfrom(BUFSIZE)
25         print('來自[%s:%s]的一條消息:\033[1;44m%s\033[0m' %(addr[0],addr[1],back_msg.decode('utf-8')))
26 
27 udp_client_socket.close()
#UDP_client1
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # _author_soloLi
 4 import socket
 5 BUFSIZE=1024
 6 udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
 7 
 8 qq_name_dic={
 9     '狗哥alex':('127.0.0.1',8081),
10     '瞎驢':('127.0.0.1',8081),
11     '一棵樹':('127.0.0.1',8081),
12     '武大郎':('127.0.0.1',8081),
13 }
14 
15 
16 while True:
17     qq_name=input('請選擇聊天對象: ').strip()
18     while True:
19         msg=input('請輸入消息,回車發送: ').strip()
20         if msg == 'quit':break
21         if not msg or not qq_name or qq_name not in qq_name_dic:continue
22         udp_client_socket.sendto(msg.encode('utf-8'),qq_name_dic[qq_name])
23 
24         back_msg,addr=udp_client_socket.recvfrom(BUFSIZE)
25         print('來自[%s:%s]的一條消息:\033[1;44m%s\033[0m' %(addr[0],addr[1],back_msg.decode('utf-8')))
26 
27 udp_client_socket.close()
#UDP_client2

5、粘包現象:①發送端需要等緩衝區滿才發送出去,造成粘包(發送數據時間間隔很短,數據了很小,TCP有一個Nagle演算法會把數據合到一起,產生粘包)
                       ②接收方不及時接收緩衝區的包,造成多個包接收(客戶端發送了一段數據,服務端只收了一小部分,服務端下次再收的時候還是從緩衝區拿上次遺留的數據,產生粘包)

原因:接收方不知道消息之間的界限,不知道一次性提取多少位元組的數據。

TCP有粘包現象,UDP永遠不會粘包:tcp是基於數據流的,收發兩端都要有一一成對的socket,TCP採用Nagle優化演算法消息進行消息處理機制,面向流的通信是無消息保護邊界的。而udp是基於數據報的,支持的是一對多的模式,套接字緩衝區採用了鏈式結構來記錄每一個到達的UDP包,在每個UDP包中添加了消息頭(消息來源地址,埠等信息),面向消息的通信是有消息保護邊界的。

tcp是可靠傳輸,udp是不可靠傳輸:tcp在數據傳輸時,發送端先把數據發送到自己的緩存中,然後協議控制將緩存中的數據發往對應端,對應端返回一個ack=1,發送端則清理緩存中的數據,對端返回ack=0,則重新發送數據,所以tcp是可靠的;而udp發送數據,對端是不會返回確認信息的,因此不可靠。

解決粘包:問題的根源在於,接收端不知道發送端將要傳送的位元組流的長度,所以解決粘包的方法就是圍繞,如何讓發送端在發送數據前,把自己將要發送的位元組流總大小讓接收端知曉,然後接收端來一個死迴圈接收完所有數據。

第一種解決方案:(low)

 1 #server端
 2 
 3 #!/usr/bin/env python
 4 # -*- coding:utf-8 -*-
 5 # _author_soloLi
 6 from socket import *    #由於 socket 模塊中有太多的屬性。我們在這裡破例使用了'from module import *'語句。使用 'from socket import *',我們就把 socket模塊里的所有屬性都帶到我們的命名空間里了,這樣能 大幅減短我們的代碼。
 7 import subprocess
 8 ip_port=('127.0.0.1',8080)
 9 back_log=5
10 buffer_size=1024
11 
12 server=socket(AF_INET,SOCK_STREAM)
13 server.bind(ip_port)
14 server.listen(back_log)
15 
16 while True:       #鏈接迴圈
17     conn,addr=server.accept()
18     print('新的客戶端鏈接',addr)
19     while True:   #通信迴圈
20         
21         ##//收數據//##
22         try:
23             cmd=conn.recv(buffer_size)
24             if not cmd:break
25             print('收到客戶端的命令',cmd)
26 
27             #執行命令,得到命令的運行結果cmd_res
28             
29             #subprocess模塊提供了一種一致的方法來創建和處理附加進程,與標準庫中的其它模塊相比,提供了一個更高級的介面。用於替換如下模塊:os.system() , os.spawnv() , os和popen2模塊中的popen()函數,以及 commands(). 
30             res=subprocess.Popen(cmd.decode('utf-8'),shell=True, #解碼(bytes->str)
31                                  stderr=subprocess.PIPE,
32                                  stdout=subprocess.PIPE,
33                                  stdin=subprocess.PIPE)
34             
35             err=res.stderr.read()
36             if err:
37                 cmd_res=err
38             else:
39                 cmd_res=res.stdout.read()                ##編碼是以當前所在的系統為準的,如果是windows,那麼res.stdout.read()讀出的就是GBK編碼的,在接收端需要用GBK解碼且只能從管道里讀一次結果
40 
41          ##//發數據//##
42             if not cmd_res:
43                 cmd_res='執行成功'.encode('gbk')    #轉換編碼(gbk->unicode)(轉換顯示中文的字元串)
44 
45             length=len(cmd_res)
46             conn.send(str(length).encode('utf-8'))  #編碼(str->bytes)
47             client_ready=conn.recv(buffer_size)
48             if client_ready == b'ready':
49                 conn.send(cmd_res)
50         except Exception as e:
51             print(e)
52             break
TCP_serve
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # _author_soloLi
 4 from socket import *
 5 ip_port=('127.0.0.1',8080)
 6 back_log=5
 7 buffer_size=1024
 8 
 9 client=socket(AF_INET,SOCK_STREAM)
10 client.connect(ip_port)
11 
12 while True:
13     cmd=input('>>: ').strip()
14     if not cmd:continue
15     if cmd == 'quit':break
16 
17     client.send(cmd.encode('utf-8'))  #編碼(str->bytes)
18 
19     #解決粘包
20     length=client.recv(buffer_size) 
21     client.send(b'ready')
22 
23     length=int(length.decode('utf-8')) #解碼(bytes->str)
24 
25     recv_size=0
26     recv_msg=b''
27     while recv_size < length:
28         recv_msg += tcp_client.recv(buffer_size)
29         recv_size=len(recv_msg) #1024
30 
31     print('命令的執行結果是 ',recv_msg.decode('gbk')) #轉換編碼(gbk->unicode)(轉換顯示中文的字元串)
32 client.close()
TCP_client

low的原因:程式的運行速度遠快於網路傳輸速度,所以在發送一段位元組前,先用send去發送該位元組流長度,這種方式會放大網路延遲帶來的性能損耗

第二種解決方案:(NB)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # _author_soloLi
 4 from socket import *    #由於 socket 模塊中有太多的屬性。我們在這裡破例使用了'from module import *'語句。使用 'from socket import *',我們就把 socket模塊里的所有屬性都帶到我們的命名空間里了,這樣能 大幅減短我們的代碼。
 5 import subprocess
 6 ip_port=('127.0.0.1',8080)
 7 back_log=5
 8 buffer_size=1024
 9 
10 server=socket(AF_INET,SOCK_STREAM)
11 server.bind(ip_port)
12 server.listen(back_log)
13 
14 while True:       #鏈接迴圈
15     conn,addr=server.accept()
16     print('新的客戶端鏈接',addr)
17     while True:   #通信迴圈
18         
19         ##//收數據//##
20         try:
21             cmd=conn.recv(buffer_size)
22             if not cmd:break
23             print('收到客戶端的命令',cmd)
24 
25             #執行命令,得到命令的運行結果cmd_res
26             
27             #subprocess模塊提供了一種一致的方法來創建和處理附加進程,與標準庫中的其它模塊相比,提供了一個更高級的介面。用於替換如下模塊:os.system() , os.spawnv() , os和popen2模塊中的popen()函數,以及 commands(). 
28             res=subprocess.Popen(cmd.decode('utf-8'),shell=True, #解碼(bytes->str)
29                                  stderr=subprocess.PIPE,
30                                  stdout=subprocess.PIPE,
31                                  stdin=subprocess.PIPE)
32             
33             err=res.stderr.read()
34             if err:
35                 cmd_res=err
36             else:
37                 cmd_res=res.stdout.read()                ##編碼是以當前所在的系統為準的,如果是windows,那麼res.stdout.read()讀出的就是GBK編碼的,在接收端需要用GBK解碼且只能從管道里讀一次結果
38 
39          ##//發數據//##
40             if not cmd_res:
41                 cmd_res='執行成功'.encode('gbk')    #轉換編碼(gbk->unicode)(轉換顯示中文的字元串)
42 
43             length=len(cmd_res)
44             conn.send(str(length).encode('utf-8'))  #編碼(str->bytes)
45             client_ready=conn.recv(buffer_size)
46             if client_ready == b'ready':
47                 conn.send(cmd_res)
48         except Exception as e:
49             print(e)
50             break
TCP_server
	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • #文件操作(寫入文件,讀取文件) #寫入文件 #1.打開文件(打開冰箱) fp = open('test.txt','w') print(fp,type(fp)) #2.寫入文件(把大象塞進去) fp.write('什麼時候你會覺得不再年輕了?') #3.關閉文件(關上冰箱) fp.close() ... ...
  • 通過指定下標的方式來獲得某一個數據元素,或者通過指定下標範圍來獲得一組序列的元素,這種訪問序列的方式叫做切片。有些地方也把它稱之為分片。 關於切片的工作方式,可以參考我之前寫的文章:Python中切片的工作原理 先從底層分析切片運算:list的切片,內部是調用__getitem__,__setite ...
  • qt中的進程使用需要用到頭文件:include<QProcess> 首先來看看需要用到的主要的函數 (1)進程的定義: (2)進程的初始化: (3)啟動進程 (4)使用進程讀取數據 (5)字元拼接QStringList的使用方法 頭函數:process.h 源文件:process.cpp ...
  • 最近在上生物信息學原理,打算記錄一些課上的作業。第一次作業:如題。 基本思路: 1.從GFF中讀取CDS的起始終止位置以及正負鏈信息。GFF格式見 http://blog.sina.com.cn/s/blog_8a4f556e0102yd3l.html. 2.利用起始/終止位置等信息從FNA文件中提 ...
  • Java虛擬機數據運行時區域 方法區(Method Area) 存儲載入的類信息,常量,靜態變數,編譯器編譯後的代碼等數據。雖然JVM規範把方法區描述為堆的一個邏輯部分,但它卻有一個別名叫做Non-Heap。Class文件中除了有類的版本,欄位,方法,介面等描述信息外,還有一項是常量池,用於存放編譯 ...
  • 這一周,針以往剛開始學過的基礎知識,開始進行簡單的梳理複習,以求加深對相關知識點的理解與掌握。 一·創建第一個簡單的c語言 /*this is first program !*/(/*註釋符,內容輸出不顯示) #include "stdio.h"//預處理指令 int main()//主函數,必有且 ...
  • 字典中 嵌套字典 如同json 對象, data={ "msg":{ “xxx.com”:["a","b"] } } data.values();#列印所有的值,不包括key data["meg"][“xxx.com”][1]=c;#b值變成c data.setdefault(key,value); ...
  • Elasticsearch 是一個實時的分散式搜索分析引擎, 它能讓你以一個之前從未有過的速度和規模,去探索你的數據。 它被用作全文檢索、結構化搜索、分析以及這三個功能的組合。-- 權威指南Elasticsearch版本:6.0一、安裝1、從官網下載Elasticsearch:https://www... ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...