中国开发网: 论坛: Delphi/BCB: 贴子 500680
pcplayer: Indy 10
Indy 10 的新变化- -



Indy 10 Overview

Indy 10 contains many new features, especially relating to the portion referred to as super core. Indy 10 core has been further abstracted for easier expansion. Indy 10 core also contains many new capabilities, and performance enhancements.





Indy 10 Status

Indy 10 is still under development however it is on the fast track to release in late 2003. The consistency of the current code can be likened to that of gelatin.



The SuperCore package is still under heavy construction, however the core and protocol packages have settled down and are fairly stable.





Installing Concurrent Versions

You may find it desirable while to have more than one versions of Indy installed on your system. I have 8 versions, however I do not recommend that the average user install this many. An average user will likely install 2 versions, Indy 9 and Indy 10.



This is possible with some minimal side effects. To do this perform the following steps:



1. Remove Indy 9 from your library path in Tools, Environment Options, Library

2. Install Indy 10 in a separate directory from Indy 9.

3. For each application that uses Indy, explicitly add the path for Indy 9 or Indy 10 to the search path in the project's options (Project, Options, Directories / Conditionals Tab).



Only one version of Indy can be installed at a given time on the palette. Normally I keep 10 installed on my palette and use the above technique to allow me to continue to compile applications written in 9. However some properties have changed and this can cause problems with editing / debugging of Indy 9 based applications, although I can still compile and edit source. If I must edit a DFM containing an Indy 9 component I quickly change the installed package.



If you are working primarily with one version or another with only occasional use of the other version, the above technique will work quite well and you can recompile the Indy packages on demand if necessary.



If you are not working primarily with one version you can have the binaries of the packages and the .dcp files reside in the specific Indy version directories and adjust which actual package is loaded by using the Packages tab in Project Options. By controlling the packages in Project Options you can control which packages each individual project uses.





Compatibility

Indy 10 does contain changes from Indy 9 and existing code will not compile without some adjustments. However with the support of the .Net platform as well as features found in SuperCore, changes have been necessary.



The core of Indy 10 has undergone massive structural changes. This will break some core code of users, but efforts have been made to preserve as much protocol and application level compatibility as possible. At times it may that seem the Indy Pit Crew takes no notice about the impact of changes on end users. However this is not true. Each interface change is evaluated, and the benefits are weighed against the disadvantages. Changes that are made, are designed in a manner so as to permit easy upgrading of existing source code with minimal effort. The Indy Pit Crew uses Indy in both private and commercial offerings, so each change is felt by the team as well.



It is the belief of the Indy Team that progress is not without some sacrifice. Through small changes to interfaces, large gains can be achieved and this a better Indy. Without such changes, the future directions are hindered, and vestigial baggage is retained. Just as Winshoes to Indy 8, and then Indy 8 to Indy 9 increased abstraction, so will Indy 10.



One of Indy's primary tenets is that it is easy to program and that it is based on a blocking model. This allows for easy development and user code does not suffer from serialization. Indy's design goal is to be easy to use, and fast enough for 95% of the end user's needs.



However in very large installations this causes excessive context switching and accumulated high thread overhead. These limitations appear only in large installations, at around 2,000 concurrent threads in a well designed application. In most applications limitations in user code appear long before the limitations of Indy.



Traditionally to serve the remaining 5% of the users, easily written code must be abandoned for complex and hard to maintain code such as direct overlapped I/O, I/O completion ports, or highly divided work units using threads against non blocking sockets. Indy 10 preserves Indy's easy to use blocking model, while making performance increases internally. Indy 10 does this by using advanced network interfaces and efficiently translating such back to a user friendly blocking model. Indy 10 thus is intended to serve 99.9% of the community's needs, with only a very small minority still requiring custom code for very unusual situations.



Indy 10 achieves this in many ways, but fibers are the keystone to this achievement. A fiber is very similar to a thread, but it is more flexible, and has lower overhead than a thread if used properly.



Most of the changes have affected Core, which means that users who solely use the protocol components will see very few changes. The developers who will feel the largest impact are the users directly using core components such as TIdTCPClient, and especially TIdTCPServer.





Migration

If you upgrade to Indy 10 now, it will be necessary for you to perform various manual conversions. The amount of work varies, but impacts greatly those users directly using TIdTCPServer.



The Indy Documentation team is working on a comprehensive migration guide that will be released at a later time. In addition, the Indy team is also performing an updated impact analysis and evaluating custom property readers as well as conversion utilities.



A custom property reader would upgrade DFM's automatically as each DFM is loaded into the IDE and convert the appropriate properties to Indy 10.



A conversion utility would scan DFM's and / or source files and make as many conversions as possible.





Major Changes and Additions

This section will attempt to cover and detail the major changes and additions in Indy 10. It is not a complete list of every change and addition.



.Net Support

Indy 10 will suport the .Net platform via DCCIL (Delphi for .Net compiler).



Only Core and Protocols will be supported. SuperCore is not scedules in the near future to be ported. Not all portions of these packages will be released for .Net in the first release. The .Net support initially will include TCP client, TCP server, UDP client, UDP server, and the popular protocols such as HTTP, NNTP, SMTP, POP3, and more.



Porting to the .Net platform has been prepared for previously during the Indy 10 development cycle and is now actively under way. It is targetted to be released to be available shortly after Delphi 8 is released.



The first release of Indy for .Net will be designed to work with Delphi 8. Because it is .Net, it will also work with any other .Net language including C#, VB.Net, and J#. However other IDE's such as Visual Studio.net require extra design time support for components to be used in the designer. It is planned to provide such support later. Until such support is provided, Indy for .Net will only be available in the code window while using Visual Studio.net.





Separation of Packages

Indy 10 has been separated into three packages: Core, Protocols, and SuperCore.



The Core package (IndyCore.dpk) contains all of the core pieces, base client components, and base server components. Core does not implement any higher level protocols.



The Protocols package (Indy.dpk) uses core and implements higher level protocols such as POP3, SMTP and HTTP.



The SuperCore package (IndySuperCore.dpk) contains the new features for scalable servers and massively parallel clients.



Indy 10 Packages




This allows the Indy Pit Crew to better focus on specific parts. It also benefits users who are implementing custom protocols and may not need the protocols package.



Indy 10 Package Structure




The packages have been built such that Core can operate independently from the other packages. Both Protocols and SuperCore require core, but neither Protocols or SuperCore requires each other. They can however be used in conjunction allowing SuperCore features to be used with Protocols.





SuperCore

The SuperCore package contains advanced functionality and will be not fully complete in the first Indy 10 release. SuperCore is designed to handle very heavily loaded servers with thousands of connections, or massively parallel clients in which thousands of clients must be created and used concurrently.



SuperCore also implements Fibers, Fiber Schedulers, and IOCP (I/O Completion Ports). These components while required for the overall function of SuperCore, can also be used independently by developers.



SuperCore also creates additional overhead and should only be used when such scalability is required. With smaller and medium size projects (Most projects fall into one of these two categories), using SuperCore can actually slow down your application. This is because SuperCore is a bit like a Boeing 747, while without SuperCore Indy is like a smaller commuter plane. If you are flying a short distance and only have 30 passengers, the economics of a 747 do not make sense. A commuter plane is perfect. However if you have 300 passengers to go from Pittsburgh to London, a 747 makes perfect sense. SuperCore versus Core is a bit like this.



Currently SuperCore also requires:

? Windows 2000, 2003, or XP

? Delphi 7



Windows 95, 98, and ME are not supported. Not only do they not contain the necessary support functions in all areas, but they are not designed for hosting servers and would negate any benefits provided by SuperCore. Any port to these operating systems would require extra effort and would be of use only academically.



Only Delphi 7 is supported because of changes in the VCL between versions. It is possible to support Delphi 6 and even Delphi 5, however this significantly increases testing as critical parts of the VCL vary. At this time there is no plans to support Delphi 5 or 6 because of such maintenance issues.







TCP Server

TIdTCPServer has received the largest impact of the changes in Indy 10. While efforts are planned in the future to provide for automatic conversion, there will remain some changes that are necessary to be performed manually. This section will cover the major changes independent of any conversions that may be performed automatically in the future.





Server Split

In Indy 9, TIdTCPServer contained all the necessary code and properties for command handlers. In Indy 10, the command handler functionality has been separated into a separate component named TIdCmdTCPServer which descends from TIdTCPServer.



This allows those implementing binary servers and other servers not requiring command handlers to be implemented on the base TCP server. This also allows for future expansion of TIdCmdTCPServer without adding extra baggage to TIdTCPServer.



TCP Server Split




In essence, the old TIdTCPServer is now TIdCmdTCPServer, and the new TIdTCPServer is a subset. This introduces a DFM problem however when old projects are loaded. The IDE will try to load the components by name. In Indy 10 this causes a the new TIdTCPServer to be loaded with less properties.



If you are not using command handlers you can click "Ignore All" when the IDE prompts you to upgrade the DFM.



If you are using command handlers, you need to manually edit the DFM and change the class type to TIdCmdTCPServer.





DFM Breakage

In addition to the server split, some properties have changed that cause DFM incompatibility. The primary property change is the sub properties of TIdReply which is used in the TCP Server's .Greeting and other properties.



Formerly the reply class contained both a NumericCode and TextCode property to accomodate the non standard POP3 protocol. In Indy 10, both of these properties have been consolidated into a single Code property and are handled by polymorphism for each separate protocol type.



However when the IDE loads a TIdTCPServer, for each instance of a reply it will be unable to find NumericCode or TextCode. You can manually edit the DFM and change each to Code, or use "Ignore All". If you used replies however, "Ignore All" will lose any values stored previously. If you did not use the reply properties, "Ignore All" is an option as it will be just ignoring default values which will be restored.



In the future it is planned to create custom readers to convert the older values.



Raw Reads and Writes

All raw reads and writes including Read, ReadLn, Write, WriteLn, etc are now part of the IOHandler instead of the TCPConnection.



This change was performed for two reasons.



The first reason is to isolate the raw I/O from the protocol descendants so that protocol component users only have access to the protocol methods. That is, WriteLn is normally not used by users of the HTTP client. It is only useful to such users if they are adding custom code to existing functionality. In such cases, it is still available but is now not available directly from the HTTP client. It must be referenced from the HTTP client's IOHandler property.



The second reason is one of polymorphism. When the raw I/O methods were part of the connection they could not be easily reimplemented by different IOHandlers except at a low level. Moving higher level methods into the IOHandlers allows better efficiency. For more information, see IOHandler Restructuring.



In most cases updating source code is easy. Just insert IOHandler. in front of the I/O call.



Adjustment for Server Code




Clients are adjusted the same, but do not have the Connection object, the clients are the connection object. In many TCP servers the I/O code is wrapped in a with statement. Thus the change only needs to be made in one place.



New Event Sigature

Since mose server events were threaded, an argument (AThread) was passed in to specify that thread. This included OnConnect, OnExecute and others.



In Indy 9, an example OnExecute looked like this:



procedure TformMain.IdTCPServer1Execute(AThread: TIdPeerThread);

var

i: Integer;

begin

for i := 1 to 15 do begin

AThread.Connection.WriteLn(IntToStr(i));

Sleep(1000);

end;

AThread.Connection.Disconnect;

end;



In Indy 10, the code must be adjusted as follows. The changes are highlighted.



procedure TformMain.IdTCPServer1Execute(AContext: TIdContext);

var

i: Integer;

begin

for i := 1 to 15 do begin

AContext.Connection.IOHandler.WriteLn(IntToStr(i));

Sleep(1000);

end;

AContext.Connection.Disconnect;

end;



In summary, AThread is changed to AContext in most cases, and IOHandler is inserted before raw I/O methods.



The events are still executing in a thread. In Indy 9, each connection was assigned to one thread. In Indy 10 in some cases it is possible that a single connection will be handled at different times by different threads. For example, the OnConnect may be called from on thread, the OnExecute from another, and the OnExecute yet another.





Contexts

In Indy 9, connection information could be stored in AThread.Data, or in fields added to a custom descendant of TIdPeerThread. Because Indy 10 does not assign a unique thread to each connection, this storage association is no longer available and therefore had to be separated from the thread class.



Instead Indy 10 provides a context in the form of TIdContext. TIdContext has a .Data property just as TIdPeerThread did. You can also create custom descendants of TIdContext and tell the server to use it instead by setting the ContextClass property.



The context that is passed into each event is uniquely identified and associated with a specific connection. The context does not represent the connection itself, but only session information related to the connection. Indy manages the association automatically.



To migrate such code to Indy 10, simply change your reference or ancestor class to TIdContext.





Schedulers

TCP Servers in Indy 9 had a ThreadMgr property to allow specification of an alternate thread manager such as the TIdThreadMgrPool component which offered thread pooling.



This property has been eliminated and replaced by the Scheduler property. The scheduler property still allows use of the thread managers, but also allows for advanced schedulers in SuperCore for scheduling fibers.





Super Core

Network Interfaces

Indy previously implemented only one network interface. On Windows this interface was Winsock, and on Linux the BSD socket interface. Indy still implements these interfaces but also implements more efficient optional interfaces under Windows. At this time no other interfaces have been implemented under Linux, but may be in the future. The need is less urgent under Linux because its network implementation.



Some of the additional interfaces are not available under all versions of Windows and should be used only in server implementations, or systems with a very large number of client connections. There is no need for such implementations in normal client applications. The additional network interface is IOCP (I/O Completion Ports).



Normally to use IOCP, complicated and highly unintuitive code must be written. However with Indy, just as before, Indy takes care of all these details and presents the developer with a friendly easy to use interface.





IOHandler Restructuring

To provide performance enhancements the IOHandlers in Indy have been restructured and given a more important role. Previously the role of an IOHandler was to do only very basic I/O consisting of only the following functions:



? Open (Connect)

? Close (Disconnect)

? Read raw data

? Write raw data

? Check connection status



This role allowed for alternate IOHandlers to be created that performed the I/O from sources other than a socket. Even the default socket I/O was implemented using a default IOHandler.



Because the functionality was minimal, implementing IOHandlers was very straightforward. However this also often caused the IOHandlers to perform their I/O with less efficient methods. For example, an I/O handler may be receiving data from a local file to write, but it would have no way of knowing such because it only has one write method for all data. Even if the I/O handler had the capability of a high performance file read, it could not use it.



Indy's IOHandlers now implement not only the minimal low level methods, but high level methods as well. Such higher level methods were previously implemented by TIdTCPConnection.



IOHandlers can be created as before by implementing only the low level methods. The base IOHandler contains default implementations of the higher level methods which use the lower level methods. However each IOHandler can override additional higher level methods to provide optimized implementations specific to the IOHandler.





Fibers

In addition to expanding thread support, Indy now contains support for fibers. What is a fiber?



In short, its a "Thread" but one that is controlled by code - not the operating system. In fact, a thread may be thought of as an advanced fiber. Fibers are similar to user threads in Unix.



A thread is a basic unit that the operating system allocates time to. A thread contains its own stack, certain processor registers, and a thread context. Threads are automatically scheduled by the operating system.



In general, fibers do not provide advantages over a well-designed multi threaded application. However fibers combined with an intelligent scheduler that has pertinent information available to it significantly increase performance through large efficiency gains.



Multiple fibers can be run using a single thread. A single fiber can be run by multiple threads, although only one at thread at a time can run a single fiber. You can run multiple fibers inside. The code to perform this can be quite complex, but Indy handles all this for you. All Indy components, both clients and servers support fibers, and in a transparent manner.



By using fibers, Indy is also able to translate the complex and unfriendly lower layer network interfaces into a developer friendly interface.



Fibers have been implemented as part of SuperCore and in Windows only at this time.





Schedulers

Indy's fiber weaver is a scheduler which schedules fibers onto one or more threads. Fibers deposit work items into a work queue and then wait. When a fiber's work item has been completed, the scheduler puts the fiber in a list of fibers that can be scheduled.



Operating system schedulers schedule threads in an intelligent manner, however they have limited information about threads as each thread is common and generic among all tasks in a system. Operating system schedulers can only schedule based on the wait state, and priority of a thread.



Indy's fiber weaver (fiber scheduler) uses advanced information that is specific to the task to determine scheduling needs, priorities and wait states. By doing so Indy is able to drastically reduce the number of context switches that occur relative to the work completed. This results in significant performance gains.



A context switch is when one thread is suspended and another is scheduled. To perform this the operating system must preemptively interrupt the execution path of the processor and save the context of the thread by storing several processor registers in memory. It must then restore another thread by loading processor registers from another memory location, and resume the thread's execution path.



Thread schedulers must balance the need to reduce context switching, with the need to make sure each thread receives enough processor time. Switching to often increases overhead and cause overhead to increase beyond any benefits. Switching not often enough causes unnecessary inter thread wait dependencies, and sluggish responses because threads are not receiving enough processor time.



To manage this, operating systems define a quantum, or a maximum time slice that a thread may receive processor time per switch. In most cases a thread will yield prior to this time being reached by entering a wait state. Wait states occur explicitly, or more commonly implicitly by making an operating system call, or I/O call which cannot be completed immediately. When such a call occurs, the operating system accepts the yield and switches to another thread. If the thread is waiting on I/O or some other blocking operation it will be placed in a wait state and not considered for scheduling until the requested operation has completed, or timed out.



Indy's fiber weavers work in a similar fashion, but determine wait states at a much higher level using a wider range of information. Fibers can be determined before hand to be in wait states without the need to context switch to them and wait for them to enter a wait state. Indy also divides the work between fibers and chain engines which now perform much of the low level work.



The division of labor allows for more efficient network interfaces to be used such as I/O completion ports. I/O completion ports are more efficient because they run at a level closer to the hardware interface. Winsock and other calls which are farther from the hardware interface layer must communicate with the kernel to perform the actual call to the hardware interface. Calls which communicate with the kernel must undergo context switching to do so. Thus each Winsock call often involves many unnecessary context switches just to perform its function.



Schedulers can use a single thread, multiple threads, threads on demand, or even a thread pool.



Fiber Weaver Using Single Thread




Fiber Weaver Using Multiple Threads






Work Queues

Work queues are first in first out (FIFO) queues which hold the work items requested by fibers. Most of this functionality is completely transparent to the average developer and Indy uses this functionality internally.



.





Chains

The system of work queues, schedulers, and chain engines in Indy are referred to as chains. While chains are used by Indy, they are not limited to Indy's internal use and have end user applications as well.



When chains are used, a chain based IOHandler deposits work items into the associated work queue. The fiber is then suspended until a unit of work for it has been completed. This is because the fiber can do nothing until the result of some

work is ready to be processed. Each IOHandler method is reduced to one more or more work tasks. For best performance, each method should resolve to as few specialized work tasks as possible.



A scheduler then manages the fibers while they wait for their work items to be processed. Finally, a chain engine processes the requests in the work queue and communicates with the schedulers.



Chain Structure




Chain Engines

A chain engine is the lowest level of the chain system. The chain engine performs all of the actual input and output. The chain engine may consist of a single thread, or several.



The job of a chain engine is to extract tasks from a work queue and complete the tasks. Upon completion of each task, the chain engine notifies the scheduler and the scheduler evaluates which fiber should be considered for scheduling. The chain engine then moves on to the next task in the work queue.



If there are no items in the work queue, the chain engine remains idle.



Multiple chain engine types can be implemented to implement I/O completion ports, Winsock, Overlapped I/O, or other. Indy currently only implements IOCP. While Winsock is possible and was used early on for testing, it is slow and is only of academic use.





SSL

SSL Core

The SSL capabilities of Indy 10 are now completely pluggable. Prior to Indy 10, the SSL support was pluggable at the TCP level, however protocols such as HTTP which used SSL for HTTPS were fixed to use Indy's default SSL implementation of OpenSSL.



Indy 10 continues to include support for OpenSSL, however the SSL capabilities of Indy are completely pluggable at the core and protocol level for other implementations.



SSL and other encryption methods are in the works from both the third parties SecureBlackbox and StreamSec.



SSL Protocols

Indy 10 now supports both implicit TLS and explicit TLS in the following clients and servers:



? POP3

? SMTP

? FTP

? NNTP

? IMAP4









SASL

The SASL support code has been redesigned so it is usable with POP3 and IMAP4. Indy now supports anonymous SASL, plain SASL, OTP (one-time-only password system) SASL, external SASL, and Auth Login.



FTP

FTP Client

The FTP Client has been expanded in the following ways:



? MLST and MLSD are now supported. This provides a standard FTP directory list format that is easily parsed.

? A special combine command has been added for multipart upload support. Note that this does require a server that supports the COMB command such as GlobalScape Secure FTP Server or the server component in Indy 10.

? A XCRC command has been added for obtaining the CRC of files. Note that this does require a server that supports the COMB command such as GlobalScape Secure FTP Server or the server component in Indy 10.

? The client now supports the MDTM command for obtaining the last modified date

? OTP (One-Time-Only password) calculator built in and OTP now automatically detected

? FTPX or Site to site file fransfer (where a file is transfered between two servers) is now supported. Note that FTPX transfers will only work if the server supports it (many administrators and developers now disable this capability for security reasons).

? FTP specific IP6 extensions have been added.



FTP Server

FTP Server now supports:



? MFMT command and MFF. http://www.trevezel.com/downloads/draft-somers-ftp-mfxx-00.html

? XCRC and COMB commands for supporting Cute FTP Pro's multi-part ifle update.

? Support for MD5 and MMD5 commands (http://ietfreport.isoc.org/ids/draft-twine-ftpmd5-00.txt)

? Support for some Unix switches that effect how the directory is given and this includes Recursive directory lists (-R).

? Easily Parsed List format is supproted on the FTP server. (http://cr.yp.to/ftp/list/eplf.html).

? OTP calculator user manager can be used with the FTP server.

? A virtual system component can now be used to make FTP Server much easier.

? FTP specific IP6 extensions have been added.

? Implicit and explicit SSL support.



Also FTPX site to site transfers capability can now be disabled. This is done for security reasons as the Port and PASV commands are subject to abuses as described by:



? http://www.cert.org/tech_tips/ftp_port_attacks.html

? http://www.kb.cert.org/vuls/id/2558

? http://www.cert.org/advisories/CA-1997-27.html

? http://www.geocities.com/SiliconValley/1947/Ftpbounc.htm

? http://cr.yp.to/ftp/security.html





FTP List Parsing

Indy 10 contains a plug in FTP list parsing system with provided parsers for nearly every FTP server type in existence, and even a few which are probably no longer functioning.



If the chance arises that an unsupported system is encoutnered, a custom handler can be used.



FTP servers supported:



? Bull GCOS 7 or Bull DPS 7000

? Bull GCOS 8 or Bull DPS 9000/TA200

? Cisco IOS

? Distinct FTP Server

? EPLF (Easily Parsed List Format)

? HellSoft FTP Server for Novell Netware 3 and 4

? HP 3000 or MPE/iX including HP 3000 with Posix

? IBM AS/400, OS/400

? IBM MVS, OS/390, z/OS

? IBM OS/2

? IBM VM, z/VM

? IBM VSE

? KA9Q or NOS

? Microware OS-9

? Music (Multi-User System for Interactive Computing)

? NCSA FTP Server for MS-DOS (CUTCP)

? Novell Netware

? Novell Netware Print Services for UNIX

? TOPS20

? UniTree

? VMS or VMS (including Multinet, MadGoat, UCX)

? Wind River VxWorks

? WinQVT/Net 3.98.15

? Xecom MicroRTOS



Other

Other notable changes and improvements to Indy 10 include but are not limited to:



? Threads can now be named. For more information, see Thread Names.

? Server intercepts have been added permitting you to log the FTP server and they work similarly to the client intercepts.

? Systat UDP and TCP client and servers have been added.

? A DNS server component has been added.

? HTTP connect through proxy support has been added.

? TIdIPAddrMon has been added for monitoring all IP addresses and all network adaptors

? IP6 support

? A One-Time-Only password system has been implmeneted as both an OTP calculator for the clients and as a user manager component. This supports MD4, MD5, and SHA1 hashes.







About the Author

Chad Z. Hower a.k.a Kudzu

Chad Z. Hower, a.k.a. "Kudzu" is the original author and project coordinator for Internet Direct (Indy). Indy consists of over 110 components and is included as a part of Delphi, Kylix and C++ Builder. Chad's background includes work in the employment, security, chemical, energy, trading, telecommunications, wireless, and insurance industries. Chad's area of specialty is TCP/IP networking and programming, inter-process communication, distributed computing, Internet protocols, and object-oriented programming. When not programming, he likes to cycle, kayak, hike, downhill ski, drive, and do just about anything outdoors. Chad, whose motto is "Programming is an art form that fights back", also posts free articles, programs, utilities and other oddities at Kudzu World at http://www.Hower.org/Kudzu/. Chad is an American ex-patriate who currently spends his summers in St. Petersburg, Russia and his winters in Limassol, Cyprus.



Chad works as a Senior Developer for Atozed Computer Software Ltd. (http://www.atozed.com)

相关信息:


欢迎光临本社区,您还没有登录,不能发贴子。请在 这里登录