久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

C#使用SocketAsyncEventArgs操作套接字的簡(jiǎn)單異步通訊

 勤奮不止 2020-07-08

SocketAsyncEventArgs是一個(gè)套接字操作的類(lèi),,主要作用是實(shí)現(xiàn)socket消息的異步接收和發(fā)送,跟Socket的BeginSend和
BeginReceive方法異步處理沒(méi)有多大區(qū)別,它的優(yōu)勢(shì)在于完成端口的實(shí)現(xiàn)來(lái)處理大數(shù)據(jù)的并發(fā)情況,由于本人學(xué)習(xí)不久,,對(duì)千萬(wàn)級(jí)的
數(shù)據(jù)訪問(wèn)還沒(méi)有多大體會(huì),這里的簡(jiǎn)單實(shí)現(xiàn)作為一個(gè)學(xué)習(xí)的筆記,請(qǐng)酌情參考,,如有錯(cuò)誤,,請(qǐng)及時(shí)指正。

先說(shuō)說(shuō)SockeAsyncEventArgs類(lèi)的操作方法,,以下是摘自MSDN的內(nèi)容(MSDN的SockeAsyncEventArgs類(lèi)描述):

1,、分配一個(gè)新的 SocketAsyncEventArgs 上下文對(duì)象,或者從應(yīng)用程序池中獲取一個(gè)空閑的此類(lèi)對(duì)象,。

1   SocketAsyncEventArgs saea = new SocketAsyncEventArgs();
2   //或者(這里的SocketAsyncEventArgsPool類(lèi)一般是自己實(shí)現(xiàn),,MSDN有通過(guò)棧結(jié)構(gòu)實(shí)現(xiàn)的程序池,也可以使用隊(duì)列或鏈表):
3   SocketAsyncEventArgs saea = new SocketAsyncEventArgsPool().Pop();

 

2,、將該上下文對(duì)象的屬性設(shè)置為要執(zhí)行的操作(例如,,完成回調(diào)方法、數(shù)據(jù)緩沖區(qū),、緩沖區(qū)偏移量以及要傳輸?shù)淖畲髷?shù)據(jù)量),。SocketAsyncEventArgs一般會(huì)根據(jù)操作執(zhí)行相同的回調(diào)函數(shù),所有設(shè)置內(nèi)容在不同操作的回調(diào)都可以訪問(wèn),,我在調(diào)試時(shí)發(fā)現(xiàn)不能同時(shí)收發(fā)消息(可能是半雙工),,因此使用接收和發(fā)送試用兩個(gè)對(duì)象

1   byte[] buffer = new byte[1024];
2   saea.SetBuffer(buffer, 0, buffer.Length);    //設(shè)置緩沖區(qū)
3   saea.Completed += new EventHandler<SocketAsyncEventArgs>(MethodName);    //設(shè)置回調(diào)方法
4   saea.RemoteEndPoint = new IPEndPoint(IPAddress.Any,1234);    //設(shè)置遠(yuǎn)端連接節(jié)點(diǎn),一般用于接收消息
5   saea.UserToken = new AsyncUserToken();     //設(shè)置用戶(hù)信息,,一般把連接的Socket對(duì)象放在這里

 

3,、調(diào)用適當(dāng)?shù)奶捉幼址椒?(xxxAsync) 以啟動(dòng)異步操作。
4,、如果異步套接字方法 (xxxAsync) 返回 true,,則在回調(diào)中查詢(xún)上下文屬性來(lái)獲取完成狀態(tài)。
5,、如果異步套接字方法 (xxxAsync) 返回 false,,則說(shuō)明操作是同步完成的。 可以查詢(xún)上下文屬性來(lái)獲取操作結(jié)果,。

復(fù)制代碼
 1   //這是調(diào)用套接字的方法,,即socket調(diào)用的方法:
 2   Socket socket = saea.AcceptSocket;
 3   socket.ConnectAsync(saea);     //異步進(jìn)行連接
 4   socket.AcceptAsync(saea);     //異步接收連接
 5   socket.ReceiveAsync(saea);     //異步接收消息
 6   socket.SendAsync(saea);     //異步發(fā)送消息
 7   //這里注意的是,每個(gè)操作方法返回的是布爾值,,這個(gè)布爾值的作用,,是表明當(dāng)前操作是否有等待I/O的情況,如果返回false則表示當(dāng)前是同步操作,,不需要等待,,此時(shí)要要同步執(zhí)行回調(diào)方法,一般寫(xiě)法是
 8   bool willRaiseEvent = socket.ReceiveAsync(saea); //繼續(xù)異步接收消息
 9   if (!willRaiseEvent)
10   {
11     MethodName(saea);
12   }
復(fù)制代碼

 

6,、將該上下文重用于另一個(gè)操作,,將它放回到應(yīng)用程序池中,或者將它丟棄。
  如果用于持續(xù)監(jiān)聽(tīng)連接,,要注意saea.AcceptSocket = null;只有把saea對(duì)象的AcceptSocket置為null,,才能監(jiān)聽(tīng)到新的連接;
  如果只用于單次通訊,,則在用完saea對(duì)象是可丟棄,,saea.Dispose(),如果想重復(fù)利用,則設(shè)置相應(yīng)的異步操作即可,,
  

1 saea.AcceptSocket = null;//重新監(jiān)聽(tīng)    
2 socket.ReceiveAsync(saea);//重新接收
3 socket.SendAsync(saea);//重新發(fā)送

 

關(guān)于具體的實(shí)現(xiàn),,類(lèi)似于之前我記下的簡(jiǎn)單Socket通信,先是SocketServerManager的實(shí)現(xiàn),,該實(shí)現(xiàn)也是參考自MSDN:

復(fù)制代碼
  1     public class SocketServerManager
  2     {
  3         readonly Socket _socket;        //監(jiān)聽(tīng)Socket
  4         readonly EndPoint _endPoint;
  5         private const int Backlog = 100;     //允許連接數(shù)目
  6         private int byteSize = 64;
  7 
  8         //同時(shí)UI界處理的事件
  9         public delegate void OnEventCompletedHanlder(MessageFormat msg);
 10         public event OnEventCompletedHanlder OnReceiveCompletedEvent;
 11         public event OnEventCompletedHanlder OnSendCompletedEvent;
 12         public event OnEventCompletedHanlder OnConnectedEvent;
 13         public event OnEventCompletedHanlder OnDisconnectEvent;
 14         public event OnEventCompletedHanlder OnNotConnectEvent;
 15 
 16         //private BufferManager bufferManager;        //消息緩存管理
 17         SocketAsyncEventArgsPool rwPool;              //SAEA池
 18         private Semaphore maxClient;
 19         private Dictionary<string, SocketAsyncEventArgs> dicSAEA = null; 
 20 
 21         public SocketServerManager(string ip, int port)
 22         {
 23             _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 24             IPAddress ipAddress = IPAddress.Parse(ip);
 25             _endPoint = new IPEndPoint(ipAddress, port);
 26             //bufferManager = new BufferManager(totalBytes, byteSize);
 27             maxClient = new Semaphore(Backlog, Backlog);
 28             Init();
 29         }
 30 
 31         public void Init()
 32         {
 33             //bufferManager.InitBuffer();
 34             SocketAsyncEventArgs rwEventArgs;
 35             rwPool = new SocketAsyncEventArgsPool(Backlog);
 36             dicSAEA = new Dictionary<string, SocketAsyncEventArgs>();
 37             for (int i = 0; i < 100; i++)
 38             {
 39                 rwEventArgs = new SocketAsyncEventArgs();
 40                 rwEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
 41                rwEventArgs.UserToken = new AsyncUserToken();
 42 
 43                 rwEventArgs.SetBuffer(new byte[byteSize],0,byteSize);
 44                 //bufferManager.SetBuffer(rwEventArgs);
 45 
 46                 rwPool.Push(rwEventArgs);
 47             }
 48         }
 49 
 50         /// <summary>
 51         /// 開(kāi)啟Socket監(jiān)聽(tīng)
 52         /// </summary>
 53         public void Start()
 54         {
 55             _socket.Bind(_endPoint);        //綁定本地地址進(jìn)行監(jiān)聽(tīng)
 56             _socket.Listen(Backlog);        //設(shè)置監(jiān)聽(tīng)數(shù)量
 57 
 58             StartAccept(null);
 59         }
 60 
 61         public void StartAccept(SocketAsyncEventArgs acceptEventArg)
 62         {
 63             if (acceptEventArg == null)
 64             {
 65                 acceptEventArg = new SocketAsyncEventArgs();
 66                 acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnectedCompleted);
 67             }
 68             else
 69             {
 70                 acceptEventArg.AcceptSocket = null;
 71             }
 72 
 73             maxClient.WaitOne();
 74             bool willRaiseEvent = _socket.AcceptAsync(acceptEventArg);
 75             if (!willRaiseEvent)
 76             {
 77                 ProcessAccept(acceptEventArg);
 78             }
 79         }
 80 
 81         private void ProcessAccept(SocketAsyncEventArgs e)
 82         {
 83             if (e.SocketError != SocketError.Success) return;       //異步處理失敗,,不做處理
 84             SocketAsyncEventArgs saea = rwPool.Pop();
 85             AsyncUserToken token = saea.UserToken as AsyncUserToken;
 86             token.UserSocket = e.AcceptSocket;       //獲取遠(yuǎn)端對(duì)話Socket對(duì)象
 87             string ipRemote = token.UserSocket.RemoteEndPoint.ToString();
 88             string ip = token.UserSocket.RemoteEndPoint.ToString();
 89             MessageFormat msg = new MessageFormat(string.Format("遠(yuǎn)程地址[{0}]成功連接到本地", ipRemote), ip, MsgType.Empty);
 90             msg.tag = MsgType.Empty;
 91             if (OnConnectedEvent != null) OnConnectedEvent(msg);            //調(diào)用UI方法處理
 92 
 93             //連接成功后,發(fā)送消息通知遠(yuǎn)程客戶(hù)端
 94             //OnSend("Connected Success !", _sendSocket.RemoteEndPoint);
 95             SocketAsyncEventArgs sendArgs = new SocketAsyncEventArgs();
 96             sendArgs.RemoteEndPoint = token.UserSocket.RemoteEndPoint;
 97             sendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
 98             sendArgs.UserToken = saea.UserToken;
 99             dicSAEA.Add(token.UserSocket.RemoteEndPoint.ToString(), sendArgs);
100             bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(saea);
101             if (!willRaiseEvent)
102             {
103                 OnReceiveCompleted(saea);
104             }
105 
106             StartAccept(e);
107         }
108 
109         /// <summary>
110         /// 遠(yuǎn)端地址連接本地成功的回調(diào)
111         /// </summary>
112         /// <param name="sender"></param>
113         /// <param name="e"></param>
114         public void OnConnectedCompleted(object sender, SocketAsyncEventArgs e)
115         {
116             ProcessAccept(e);
117         }
118 
119         public void IO_Completed(object sender, SocketAsyncEventArgs e)
120         {
121             switch (e.LastOperation)
122             {
123                 case SocketAsyncOperation.Receive:
124                     OnReceiveCompleted(e);
125                     break;
126                 case SocketAsyncOperation.Send:
127                     OnSendCompleted(e);
128                     break;
129                 default:
130                     throw new ArgumentException("The last operation completed on the socket was not a receive or send");
131             }   
132         }
133 
134         /// <summary>
135         /// 執(zhí)行異步發(fā)送消息
136         /// </summary>
137         /// <param name="msg">消息內(nèi)容</param>
138         /// <param name="ip">發(fā)送遠(yuǎn)端地址</param>
139         public void OnSend(MessageFormat mf)
140         {
141             if (!dicSAEA.ContainsKey(mf.ipStr))
142             {
143                 if (OnNotConnectEvent != null)
144                 {
145                     OnNotConnectEvent(new MessageFormat("不存在此連接客戶(hù)端","",MsgType.Empty));
146                     return;
147                 }
148             }
149             SocketAsyncEventArgs saea = dicSAEA[mf.ipStr];
150             AsyncUserToken token = saea.UserToken as AsyncUserToken;
151             if (saea == null) return;
152             //saea.SetBuffer(sendBuffer, 0, sendBuffer.Length);  //設(shè)置SAEA的buffer消息內(nèi)容
153             byte[] sendBuffer = Encoding.Unicode.GetBytes(string.Format("[length={0}]{1}", mf.msgStr.Length, mf.msgStr));
154             saea.SetBuffer(sendBuffer, 0, sendBuffer.Length);
155             bool willRaiseEvent = token.UserSocket.SendAsync(saea);
156             if (!willRaiseEvent)
157             {
158                 OnSendCompleted(saea);
159             }
160         }
161 
162         /// <summary>
163         /// 發(fā)送消息回調(diào)處理
164         /// </summary>
165         /// <param name="sender"></param>
166         /// <param name="e"></param>
167         public void OnSendCompleted(SocketAsyncEventArgs e)
168         {
169             AsyncUserToken token = e.UserToken as AsyncUserToken;
170             byte[] sendBuffer = e.Buffer;
171             string msgStr = Encoding.Unicode.GetString(sendBuffer);
172             string ipAddress = token.UserSocket.RemoteEndPoint.ToString();
173             MessageFormat msg = new MessageFormat(msgStr, ipAddress, MsgType.Send);
174             if (OnSendCompletedEvent != null) OnSendCompletedEvent(msg);        //調(diào)用UI方法處理
175         }
176 
177         /// <summary>
178         /// 接收消息回調(diào)處理
179         /// </summary>
180         /// <param name="e"></param>
181         public void OnReceiveCompleted(SocketAsyncEventArgs e)
182         {
183             if (e.SocketError != SocketError.Success) return;   //判斷消息的接收狀態(tài)
184             AsyncUserToken token = e.UserToken as AsyncUserToken;
185             int lengthBuffer = e.BytesTransferred;      //獲取接收的字節(jié)長(zhǎng)度
186             string ipAddress = token.UserSocket.RemoteEndPoint.ToString();
187             MessageFormat msg = new MessageFormat();
188             //如果接收的字節(jié)長(zhǎng)度為0,,則判斷遠(yuǎn)端服務(wù)器關(guān)閉連接
189             if (lengthBuffer <= 0)
190             {
191                 msg.msgStr = "遠(yuǎn)端服務(wù)器已經(jīng)斷開(kāi)連接";
192                 msg.ipStr = ipAddress;
193                 msg.tag = MsgType.Handler;
194                 if (OnDisconnectEvent != null) OnDisconnectEvent(msg);
195                 CloseClientSocket(e);
196             }
197             else
198             {
199                 byte[] receiveBuffer = e.Buffer;
200                 byte[] buffer = new byte[lengthBuffer];
201                 Buffer.BlockCopy(receiveBuffer, 0, buffer, 0, lengthBuffer);
202                 msg.msgStr = Encoding.Unicode.GetString(buffer);
203                 msg.ipStr = ipAddress;
204                 msg.tag = MsgType.Receive;
205                 bool willRaiseEvent = token.UserSocket.ReceiveAsync(e);     //繼續(xù)異步接收消息
206                 if (!willRaiseEvent)
207                 {
208                     OnReceiveCompleted(e);
209                 }
210                 if (OnReceiveCompletedEvent != null) OnReceiveCompletedEvent(msg);        //調(diào)用UI方法處理
211             }
212         }
213 
214         private void CloseClientSocket(SocketAsyncEventArgs e)
215         {
216             AsyncUserToken token = e.UserToken as AsyncUserToken;
217             try
218             {
219                 token.UserSocket.Shutdown(SocketShutdown.Send);
220             }
221             catch (Exception) { }
222             dicSAEA.Remove(token.UserSocket.RemoteEndPoint.ToString());
223             token.UserSocket.Close();
224 
225             maxClient.Release();
226             rwPool.Push(e);
227         }
228     }
復(fù)制代碼

 

通過(guò)一個(gè)棧結(jié)構(gòu)SocketAsyncEventArgsPool保存的SocketAsyncEventArgs對(duì)象是用于接收消息,,為了做到雙方通訊,我每次在接收到遠(yuǎn)端客戶(hù)端連接時(shí),,就創(chuàng)建一個(gè)新的SocketAsyncEventArgs對(duì)象保存在Dictionary結(jié)構(gòu)中,,這樣在消息發(fā)送是就可以根據(jù)Ip來(lái)發(fā)送給遠(yuǎn)程客戶(hù)端。

 

客戶(hù)端的實(shí)現(xiàn)比較簡(jiǎn)單,,不用考慮多方的通訊:

復(fù)制代碼
  1     public class SocketClientManager
  2     {
  3         readonly Socket _socket;      //用于消息交互的socket對(duì)象
  4         readonly EndPoint _endPoint;      //遠(yuǎn)端地址
  5         readonly SocketAsyncEventArgs _saea;        //處理連接和接收SAEA對(duì)象
  6         //處理發(fā)送的SAEA處理,,由于綁定不同的回調(diào)函數(shù),因此需要不同的SAEA對(duì)象
  7         SocketAsyncEventArgs _sendSaea;         
  8 
  9         //處理UI的事件
 10         public delegate void OnEventCompletedHanlder(MessageFormat msgFormat);
 11         public event OnEventCompletedHanlder OnConnectedEvent;       //連接成功事件
 12         public event OnEventCompletedHanlder OnReceiveCompletedEvent;        //收到消息事件
 13         public event OnEventCompletedHanlder OnSendCompletedEvent;       //發(fā)送成功事件
 14 
 15         public SocketClientManager(string ip, int port)
 16         {
 17             _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 18             IPAddress ipAddress = IPAddress.Parse(ip);
 19             _endPoint = new IPEndPoint(ipAddress, port);
 20             _saea = new SocketAsyncEventArgs {RemoteEndPoint = _endPoint};
 21         }
 22 
 23         /// <summary>
 24         /// 開(kāi)啟進(jìn)行遠(yuǎn)程連接
 25         /// </summary>
 26         public void Start()
 27         {
 28             _saea.Completed += OnConnectedCompleted;
 29             _socket.ConnectAsync(_saea);        //進(jìn)行異步連接
 30 
 31         }
 32 
 33         /// <summary>
 34         /// 連接成功的事件回調(diào)函數(shù)
 35         /// </summary>
 36         /// <param name="sender"></param>
 37         /// <param name="e"></param>
 38         public void OnConnectedCompleted(object sender, SocketAsyncEventArgs e)
 39         {
 40             if (e.SocketError != SocketError.Success) return;
 41             Socket socket = sender as Socket;
 42             string ipRemote = socket.RemoteEndPoint.ToString();
 43             MessageFormat messageFormat = new MessageFormat(string.Format("連接服務(wù)器[{0}]成功,!", ipRemote), socket.LocalEndPoint.ToString(), MsgType.Empty);
 44             if (OnConnectedEvent != null) OnConnectedEvent(messageFormat);
 45 
 46             //開(kāi)啟新的接受消息異步操作事件
 47             var receiveSaea = new SocketAsyncEventArgs();
 48             var receiveBuffer = new byte[1024 * 4];
 49             receiveSaea.SetBuffer(receiveBuffer, 0, receiveBuffer.Length);       //設(shè)置消息的緩沖區(qū)大小
 50             receiveSaea.Completed += OnReceiveCompleted;         //綁定回調(diào)事件
 51             receiveSaea.RemoteEndPoint = _endPoint;
 52             _socket.ReceiveAsync(receiveSaea);
 53         }
 54 
 55         /// <summary>
 56         /// 接受消息的回調(diào)函數(shù)
 57         /// </summary>
 58         /// <param name="sender"></param>
 59         /// <param name="e"></param>
 60         public void OnReceiveCompleted(object sender, SocketAsyncEventArgs e)
 61         {
 62             if (e.SocketError == SocketError.OperationAborted) return;
 63             var socket = sender as Socket;
 64             MessageFormat messageFormat = new MessageFormat();
 65             if (e.SocketError == SocketError.Success &&e.BytesTransferred > 0)
 66             {
 67                 string ipAddress = socket.RemoteEndPoint.ToString();
 68                 int lengthBuffer = e.BytesTransferred;
 69                 byte[] receiveBuffer = e.Buffer;
 70                 byte[] buffer = new byte[lengthBuffer];
 71                 Buffer.BlockCopy(receiveBuffer, 0, buffer, 0, lengthBuffer);
 72                 messageFormat.msgStr = Encoding.Unicode.GetString(buffer);
 73                 messageFormat.ipStr = ipAddress;
 74                 messageFormat.tag = MsgType.Receive;;
 75                 socket.ReceiveAsync(e);
 76             }
 77             else if (e.SocketError == SocketError.ConnectionReset && e.BytesTransferred == 0)
 78             {
 79                 messageFormat.msgStr = "服務(wù)器已經(jīng)斷開(kāi)連接";
 80                 messageFormat.ipStr = socket.RemoteEndPoint.ToString();
 81                 messageFormat.tag = MsgType.Handler;
 82             }
 83             else
 84             {
 85                 return;
 86             }
 87             if (OnReceiveCompletedEvent != null) OnReceiveCompletedEvent(messageFormat);
 88         }
 89 
 90         /// <summary>
 91         /// 發(fā)送消息回調(diào)函數(shù)
 92         /// </summary>
 93         /// <param name="sender"></param>
 94         /// <param name="e"></param>
 95         public void OnSendCompleted(object sender, SocketAsyncEventArgs e)
 96         {
 97             if (e.SocketError != SocketError.Success) return;
 98             var socket = sender as Socket;
 99             byte[] sendBuffer = e.Buffer;
100             MessageFormat messageFormat = new MessageFormat(Encoding.Unicode.GetString(sendBuffer),socket.RemoteEndPoint.ToString(),MsgType.Send);
101             if (OnSendCompletedEvent != null) OnSendCompletedEvent(messageFormat);
102         }
103 
104         /// <summary>
105         /// 斷開(kāi)連接
106         /// </summary>
107         public void OnDisConnect()
108         {
109             if (_socket != null)
110             {
111                 try
112                 {
113                     _socket.Shutdown(SocketShutdown.Both);
114                 }
115                 catch (SocketException ex)
116                 {
117                 }
118                 finally
119                 {
120                     _socket.Close();
121                 }
122             }
123         }
124 
125         /// <summary>
126         /// 發(fā)送消息
127         /// </summary>
128         /// <param name="msg"></param>
129         public void SendMsg(MessageFormat mf)
130         {
131             byte[] sendBuffer = Encoding.Unicode.GetBytes(string.Format("[length={0}]{1}", mf.msgStr.Length, mf.msgStr));
132             if (_sendSaea == null)
133             {
134                 _sendSaea = new SocketAsyncEventArgs {RemoteEndPoint = _endPoint};
135                 _sendSaea.Completed += OnSendCompleted;
136             }
137             _sendSaea.SetBuffer(sendBuffer, 0, sendBuffer.Length);
138             if (_socket != null) _socket.SendAsync(_sendSaea);
139         }
140     }
復(fù)制代碼

 

同樣是使用收發(fā)不同的SocketAsyncEventArgs對(duì)象,。

 

另外,關(guān)于解決緩存容量不足以容納一條消息的半包問(wèn)題,,這里使用了簡(jiǎn)單的字符處理類(lèi),,這個(gè)類(lèi)是復(fù)制自Jimmy Zhang的類(lèi)RequestHandler,當(dāng)然,,方法還是不完善的,,難以解決不同順序的消息接受。


具體源碼(.net4.5,,vs2013):具體源碼 http://files.cnblogs.com/files/supheart/ServerBySocket.zip

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多