关于ConnectionManager的配置(原)

 

服务器规划
Domain  IPDescription
imserver.p2pvpn.com  172.0.7.205基于openfire的im server
cm1.p2pvpn.com  172.0.7.206Connection Manager
cm2.p2pvon.com  172.0.7.205Connection Manager
dns  172.0.7.206dns服务器

 

 

 

 

 

 

一.配置dns服务器(这里的dns仅用于内网测试)

1.db.p2pvpn.com文件,用于正向解析

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
$TTL 604800
@ IN SOA dns.p2pvpn.com. root.p2pvpn.com. (
1
604800
86400
2419200
604800 )
@ IN NS dns
dns
IN A 172.0 . 7.206
imserver
IN A 172.0 . 7.205
cm
IN A 172.0 . 7.206
cm
IN A 172.0 . 7.205

 

 

 

2.db.7.0.172文件用于反向解析(可有可无,一般反向解析很少用)

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
$TTL 604800
@ IN SOA dns.p2pvpn.com. root.p2pvpn.com. (
1
604800
86400
2419200
604800 )
@ IN NS dns
206 IN PTR dns

 

 

3.修改named.conf.local

 

 
  
zone " p2pvpn.com " {
type master;
file
" /etc/bind/db.p2pvpn.com " ;
};



zone
" 7.0.172.in-addr.arpa " {
type master;
file
" /etc/bind/db.7.0.172 " ;
};

 

 

通过上面的配置, 只需要im client通过cm.p2pvpn.com这个domain就能轮询二台Connection Manager

dns配置注意:

sudo /etc/init.d/bind9 restart

sudo vim /etc/resolv.conf:指向本地dns.

 

二.配置Connection Manager

1.修改cm1的manager.xml

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
<? xml version="1.0" encoding="UTF-8" ?>

<!--

This file stores bootstrap properties needed by Connection Managers.

Property names must be in the format: "prop.name.is.blah=value"

That will be stored as:

<prop>

<name>

<is>

<blah>value</blah>

</is>

</name>

</prop>

-->

<!-- root element, all properties must be under this element -->

< jive >

< xmpp >

<!-- Name of the server to connect. This property is required. -->

< domain > imserver.p2pvpn.com </ domain >

<!-- IP address or hostname of the XMPP server. If not defined then a DNS SRV lookup

of the domain will be performed.
-->

<!-- <hostname></hostname> -->

<!-- TCP port to connect to the XMPP server on. -->

< port > 5262 </ port >

<!-- Password to use to log into the server. This property is required. -->

< password > 1qaz2wsx </ password >

< manager >

<!-- Name of the connection manager that uniquely identifies this manager.

This property is optional. A random name is generated if none was defined.
-->

< name > cm1 </ name >

<!-- Number of connections to establish to the server. -->

< connections > 1 </ connections >

<!-- Number of threads for processing incoming server traffic per connection. -->

< incoming >

< threads > 5 </ threads >

</ incoming >

</ manager >

< server >

< certificate >

<!-- Flag that indicates if certificates of the server should be validated. -->

< verify > false </ verify >

< verify >

<!-- Flag that indicates if certificates chain should be validated. -->

< chain > true </ chain >

<!-- Verify that the the last certificate in the chain was issued by

a third-party that we trust.
-->

< root > true </ root >

<!-- For every certificate in the chain, verify that the certificate

is valid at the current time.
-->

< validity > true </ validity >

</ verify >

<!-- Flag that indicates if self-signed certificates are accepted. -->

< accept-selfsigned > false </ accept-selfsigned >

</ certificate >

</ server >

< client >

<!-- Milliseconds a client connection has to be idle to be closed.

Default is 30 minutes.
-->

< idle > 1800000 </ idle >

</ client >

< socket >

< default >

< active > false </ active >

<!-- Default port to use for plain/TLS client connections. -->

< port > 5222 </ port >

</ default >

< ssl >

< active > false </ active >

<!-- Default port to use for client connections using old SSL method. -->

< port > 5223 </ port >

< storeType > jks </ storeType >

<!-- <keystore></keystore>

<keypass></keypass>

<truststore></truststore>

<trustpass></trustpass>
-->

</ ssl >

<!-- Listen on a specific network interface. -->

<!-- <network>

<interface></interface>

</network>
-->

<!-- Low level socket settings. Use this section to finetune sockets based on load. -->

<!-- Maximum number of outstanding connection requests is set. This can be considered a backlog

of requests waiting on the TCP/IP port for the listener to accept the request.
-->

< backlog > 50 </ backlog >

< buffer >

<!-- Hint the size of the underlying buffers used by the platform for incoming network I/O -->

< receive > -1 </ receive >

<!-- Hint the size of the underlying buffers used by the platform for outgoing network I/O -->

< send > -1 </ send >

</ buffer >

<!-- Specifies a linger-on-close timeout. This option disables/enables immediate return

from a close() of a TCP Socket.
-->

< linger > -1 </ linger >

<!-- This option causes packets to be flushed on to the network more frequently. If you are

streaming large amounts of data, there is no buffering and hence no delay.
-->

<!-- <tcp-nodelay>false</tcp-nodelay> -->

</ socket >

< processor >

<!-- Number of processors that will be listening for incoming traffic. The optimal number is related

to the number of CPUs. Each processor will run in its own thread.
-->

<!-- <count>1</count> -->

<!-- Number of threads that will process incoming traffic detected by processors. Note that

threads will be shared among processors.
-->

<!-- <threads>

<standard>16</standard>

<ssl>16</ssl>

</threads>
-->

</ processor >

<!-- Configure http binding. -->

< httpbind >

< enabled > true </ enabled >

< port >

< plain > 7071 </ plain >

< secure > 7443 </ secure >

</ port >

<!-- Script syntax allows BOSH to be used in environments where clients may be restricted to using a particular server -->

< scriptSyntax >

< enabled > true </ enabled >

</ scriptSyntax >

< client >

< requests >

<!-- Longest time (in seconds) to wait before responding to any request during the session -->

<!-- <wait></wait> -->

<!-- Maximum allowable seconds over which a client can send empty requests to the server -->

< polling > 5 </ polling >

<!-- Limit number of simultaneous requests the client makes with the 'requests' attribute -->

< max > 2 </ max >

</ requests >

<!-- Seconds a session has to be idle to be closed -->

< idle > 30 </ idle >

</ client >

</ httpbind >

</ xmpp >

<!-- Configure debug logger. -->

< log >

< debug >

< enabled > false </ enabled >

</ debug >

</ log >

</ jive >

 

 

2.修改cm2的manager.xml

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
<? xml version="1.0" encoding="UTF-8" ?>

<!--

This file stores bootstrap properties needed by Connection Managers.

Property names must be in the format: "prop.name.is.blah=value"

That will be stored as:

<prop>

<name>

<is>

<blah>value</blah>

</is>

</name>

</prop>

-->

<!-- root element, all properties must be under this element -->

< jive >

< xmpp >

<!-- Name of the server to connect. This property is required. -->

< domain > imserver.p2pvpn.com </ domain >

<!-- IP address or hostname of the XMPP server. If not defined then a DNS SRV lookup

of the domain will be performed.
-->

<!-- <hostname></hostname> -->

<!-- TCP port to connect to the XMPP server on. -->

< port > 5262 </ port >

<!-- Password to use to log into the server. This property is required. -->

< password > 1qaz2wsx </ password >

< manager >

<!-- Name of the connection manager that uniquely identifies this manager.

This property is optional. A random name is generated if none was defined.
-->

< name > cm2 </ name >

<!-- Number of connections to establish to the server. -->

< connections > 1 </ connections >

<!-- Number of threads for processing incoming server traffic per connection. -->

< incoming >

< threads > 5 </ threads >

</ incoming >

</ manager >

< server >

< certificate >

<!-- Flag that indicates if certificates of the server should be validated. -->

< verify > false </ verify >

< verify >

<!-- Flag that indicates if certificates chain should be validated. -->

< chain > true </ chain >

<!-- Verify that the the last certificate in the chain was issued by

a third-party that we trust.
-->

< root > true </ root >

<!-- For every certificate in the chain, verify that the certificate

is valid at the current time.
-->

< validity > true </ validity >

</ verify >

<!-- Flag that indicates if self-signed certificates are accepted. -->

< accept-selfsigned > false </ accept-selfsigned >

</ certificate >

</ server >

< client >

<!-- Milliseconds a client connection has to be idle to be closed.

Default is 30 minutes.
-->

< idle > 1800000 </ idle >

</ client >

< socket >

< default >

< active > false </ active >

<!-- Default port to use for plain/TLS client connections. -->

< port > 5222 </ port >

</ default >

< ssl >

< active > false </ active >

<!-- Default port to use for client connections using old SSL method. -->

< port > 5223 </ port >

< storeType > jks </ storeType >

<!-- <keystore></keystore>

<keypass></keypass>

<truststore></truststore>

<trustpass></trustpass>
-->

</ ssl >

<!-- Listen on a specific network interface. -->

<!-- <network>

<interface></interface>

</network>
-->

<!-- Low level socket settings. Use this section to finetune sockets based on load. -->

<!-- Maximum number of outstanding connection requests is set. This can be considered a backlog

of requests waiting on the TCP/IP port for the listener to accept the request.
-->

< backlog > 50 </ backlog >

< buffer >

<!-- Hint the size of the underlying buffers used by the platform for incoming network I/O -->

< receive > -1 </ receive >

<!-- Hint the size of the underlying buffers used by the platform for outgoing network I/O -->

< send > -1 </ send >

</ buffer >

<!-- Specifies a linger-on-close timeout. This option disables/enables immediate return

from a close() of a TCP Socket.
-->

< linger > -1 </ linger >

<!-- This option causes packets to be flushed on to the network more frequently. If you are

streaming large amounts of data, there is no buffering and hence no delay.
-->

<!-- <tcp-nodelay>false</tcp-nodelay> -->

</ socket >

< processor >

<!-- Number of processors that will be listening for incoming traffic. The optimal number is related

to the number of CPUs. Each processor will run in its own thread.
-->

<!-- <count>1</count> -->

<!-- Number of threads that will process incoming traffic detected by processors. Note that

threads will be shared among processors.
-->

<!-- <threads>

<standard>16</standard>

<ssl>16</ssl>

</threads>
-->

</ processor >

<!-- Configure http binding. -->

< httpbind >

< enabled > true </ enabled >

< port >

< plain > 7071 </ plain >

< secure > 7443 </ secure >

</ port >

<!-- Script syntax allows BOSH to be used in environments where clients may be restricted to using a particular server -->

< scriptSyntax >

< enabled > true </ enabled >

</ scriptSyntax >

< client >

< requests >

<!-- Longest time (in seconds) to wait before responding to any request during the session -->

<!-- <wait></wait> -->

<!-- Maximum allowable seconds over which a client can send empty requests to the server -->

< polling > 5 </ polling >

<!-- Limit number of simultaneous requests the client makes with the 'requests' attribute -->

< max > 2 </ max >

</ requests >

<!-- Seconds a session has to be idle to be closed -->

< idle > 30 </ idle >

</ client >

</ httpbind >

</ xmpp >

<!-- Configure debug logger. -->

< log >

< debug >

< enabled > false </ enabled >

</ debug >

</ log >

</ jive >

 

 

注意:

由于使用grinder进行bosh的测试.所以开放了端口7071(默认是7070,但是该端口在我的机器上被占用)

 

三.启动imserver.在管理控制台-server settings-connection managers里面可以看到已经有cm1,cm2连接到imserver上.

 

四.设置grinder

1.修改one2one.py文件.

 

ContractedBlock.gif
ExpandedBlockStart.gif 代码
 
   
# The Grinder 3.0.1

# HTTP script recorded by TCPProxy at 09.Haz.2008 01:32:23



from net.grinder.script import Test

from net.grinder.script.Grinder import grinder

from net.grinder.plugin.http import HTTPPluginControl, HTTPRequest

from HTTPClient import NVPair, Codecs

from java.util import Random

from org.xml.sax import InputSource

from org.apache.xerces.parsers import DOMParser



# A shorter alias for the grinder.logger.output() method.

log
= grinder.logger.output



connectionDefaults
= HTTPPluginControl.getConnectionDefaults()

httpUtilities
= HTTPPluginControl.getHTTPUtilities()



# To use a proxy server, uncomment the next line and set the host and port.

# connectionDefaults.setProxyServer("localhost", 8001)



# These definitions at the top level of the file are evaluated once,

# when the worker process is started.



connectionDefaults.defaultHeaders
= \

( NVPair(
' User-Agent ' , ' Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14 ' ),

NVPair(
' Accept-Encoding ' , ' gzip,deflate ' ),

NVPair(
' Accept-Language ' , ' tr-TR,tr;q=0.8,en-us;q=0.5,en;q=0.3 ' ),

NVPair(
' Accept-Charset ' , ' ISO-8859-9,utf-8;q=0.7,*;q=0.7 ' ),

NVPair(
' Cache-Control ' , ' no-cache ' ),

NVPair(
' Accept ' , ' text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 ' ), )



agentID
= int(grinder.properties[ " grinder.agentID " ])

processID
= int(grinder.processName.split( " - " ).pop())

host
= ' 172.0.7.206 '
# 为了使用dns的负载均衡,使用domain.

domain
= ' cm.p2pvpn.com '

boshUrl
= ' http:// ' + domain + ' :7071/http-bind/ '

boshWait
= 1

userPrefix
= ' user '

# numThreads = 1
#
从配置文件里读取每个process下面启动多少个thread.而不是使用写死的值.
numThreads = int(grinder.properties[ " grinder.threads " ])



# Create an HTTPRequest for each request, then replace the

# reference to the HTTPRequest with an instrumented version.

# You can access the unadorned instance using request101.__target__.



request101
= Test( 101 , ' Initiate a BOSH session ' ).wrap(HTTPRequest(url = boshUrl))

request201
= Test( 201 , ' Authenticate ' ).wrap(HTTPRequest(url = boshUrl))

request301
= Test( 301 , ' Bind resource ' ).wrap(HTTPRequest(url = boshUrl))

request401
= Test( 401 , ' Request a session from the server ' ).wrap(HTTPRequest(url = boshUrl))

request501
= Test( 501 , ' Get roster ' ).wrap(HTTPRequest(url = boshUrl))

request601
= Test( 601 , ' Change presence ' ).wrap(HTTPRequest(url = boshUrl))

request701
= Test( 701 , ' Send one to one message ' ).wrap(HTTPRequest(url = boshUrl))

request801
= Test( 801 , ' Make an empty request to the server ' ).wrap(HTTPRequest(url = boshUrl))

request901
= Test( 901 , ' Terminate the session ' ).wrap(HTTPRequest(url = boshUrl))



class TestRunner:

""" A TestRunner instance is created for each worker thread. """



def __init__ (self):

log(
" agentID %s, processID %s, threadID %s ,numThreads %s " % (agentID, processID, grinder.threadNumber,numThreads))
# agentID通过./startAgent.sh 0来指定.

self.userID
= (agentID * 1000 ) + (processID * numThreads) + grinder.threadNumber

self.targetUserID
= (agentID * 1000 ) + (processID * numThreads) + (grinder.threadNumber + 1 ) % numThreads

log(
" userID %s, targetUserID %s " % (self.userID, self.targetUserID))

self.username
= userPrefix + str(self.userID)

self.password
= userPrefix + str(self.userID)



log(
" username %s, password %s " % (self.username, self.password))



self.targetUser
= userPrefix + str(self.targetUserID)

self.sid
= ""

self.rid
= Random().nextInt( 1000000 )

self.inactivity
= 0



def initSession(self):



result
= request101.POST( '' ,

' <body xmlns=\"http://jabber.org/protocol/httpbind\" rid=\" ' + str(self.rid) + ' \" content=\"text/xml; charset=utf-8\" to=\" ' + domain + ' \" secure=\"true\" wait=\" ' + str(boshWait) + ' \" ack=\"1\" hold=\"1\" xml:lang=\"en\" xmpp:version=\"1.0\" xmlns:xmpp=\"urn:xmpp:xbosh\" /> ' ,

( NVPair(
' Content-Type ' , ' text/plain; charset=utf-8 ' ), ))



self.rid
+= 1



body
= getXMLcontent(result)

self.sid
= body.getAttribute( ' sid ' )

self.inactivity
= int(body.getAttribute( ' inactivity ' ))

log(
" sid: %s, inactivity: %s " % (self.sid, self.inactivity))



log(
" getSession response: %s " % result.getText())



return result



def auth(self):



authtext
= Codecs.base64Encode( ' %s\x00%s\x00%s ' % (self.username + ' @ ' + domain, self.username, self.password)).strip()

log(
" authtext: " + authtext)

# if authtext[-1] == '\n':

# authtext = authtext[:-1]



result
= request201.POST( '' ,

' <body xmlns=\"http://jabber.org/protocol/httpbind\" rid=\" ' + str(self.rid) + ' \" sid=\" ' + self.sid + ' \"><auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\"> ' + authtext + ' </auth></body> ' ,

( NVPair(
' Content-Type ' , ' text/plain; charset=utf-8 ' ), ))



self.rid
+= 1



log(
" auth response: %s " % result.getText())



return result



def bind(self):



result
= request301.POST( '' ,

' <body xmlns=\"http://jabber.org/protocol/httpbind\" rid=\" ' + str(self.rid) + ' \" sid=\" ' + self.sid + ' \" xmpp:restart=\"true\" xmlns:xmpp=\"urn:xmpp:xbosh\" xml:lang=\"en\" to=\" ' + domain + ' \"><iq type=\"set\" id=\"bind_1\"><bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"><resource>Home</resource></bind></iq></body> ' ,

( NVPair(
' Content-Type ' , ' text/plain; charset=utf-8 ' ), ))



self.rid
+= 1



log(
" bind response: %s " % result.getText())



return result



def requestSession(self):



log(
" rid = " + str(self.rid))

result
= request401.POST( '' ,

' <body xmlns=\"http://jabber.org/protocol/httpbind\" rid=\" ' + str(self.rid) + ' \" sid=\" ' + self.sid + ' \"><iq type=\"set\" from=\" ' + self.username + ' @ ' + domain + ' /Home\" to=\" ' + domain + ' \" id=\"session_2\"><session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\" /></iq></body> ' ,

( NVPair(
' Content-Type ' , ' text/plain; charset=utf-8 ' ), ))



self.rid
+= 1



log(
" requestSession response: %s " % result.getText())



return result



def getRoster(self):



log(
" rid = " + str(self.rid))

result
= request501.POST( '' ,

' <body xmlns=\"http://jabber.org/protocol/httpbind\" rid=\" ' + str(self.rid) + ' \" sid=\" ' + self.sid + ' \"><iq type=\"get\" id=\"roster_3\"><query xmlns=\"jabber:iq:roster\" /></iq></body> ' ,

( NVPair(
' Content-Type ' , ' text/plain; charset=utf-8 ' ), ))



self.rid
+= 1



log(
" getRoster response: %s " % result.getText())



return result



def changePresence(self, show):



result
= request601.POST( '' ,

' <body xmlns=\"http://jabber.org/protocol/httpbind\" rid=\" ' + str(self.rid) + ' \" sid=\" ' + self.sid + ' \"><presence from=\" ' + self.username + ' @ ' + domain + ' /Home\"><show> ' + show + ' </show></presence></body> ' ,

( NVPair(
' Content-Type ' , ' text/plain; charset=utf-8 ' ), ))



self.rid
+= 1



log(
" changePresence %s response: %s " % (show, result.getText()))



return result



def sendMessage(self, message, target):



result
= request701.POST( '' ,

' <body xmlns=\"http://jabber.org/protocol/httpbind\" rid=\" ' + str(self.rid) + ' \" sid=\" ' + self.sid + ' \"><message type=\"chat\" from=\" ' + self.username + ' @ ' + domain + ' /Home\" to=\" ' + target + ' @ ' + domain + ' \"><body> ' + message + ' </body></message></body> ' ,

( NVPair(
' Content-Type ' , ' text/plain; charset=utf-8 ' ), ))



self.rid
+= 1



log(
" sendMessage response: %s " % result.getText())



return result



def poll(self):



result
= request801.POST( '' ,

' <body xmlns=\"http://jabber.org/protocol/httpbind\" rid=\" ' + str(self.rid) + ' \" sid=\" ' + self.sid + ' \" /> ' ,

( NVPair(
' Content-Type ' , ' text/plain; charset=utf-8 ' ), ))



self.rid
+= 1



log(
" poll response: %s " % result.getText())



return result



def terminate(self):



result
= request901.POST( '' ,

' <body xmlns=\"http://jabber.org/protocol/httpbind\" rid=\" ' + str(self.rid) + ' \" sid=\" ' + self.sid + ' \" type=\"terminate\"><presence type=\"unavailable\" from=\" ' + self.username + ' @ ' + domain + ' /Home\" to=\" ' + domain + ' \" /></body> ' ,

( NVPair(
' Content-Type ' , ' text/plain; charset=utf-8 ' ), ))



self.rid
+= 1



log(
" terminate response: %s " % result.getText())



return result



def __call__ (self):

""" This method is called for every run performed by the worker thread. """



self.initSession()

self.auth()

self.bind()

self.requestSession()

self.getRoster()



message
= " Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis rutrum porttitor ante. Nunc arcu leo. "

show
= " chat "



# for i in range(2):

while (True):

if show == " dnd " :

show
= " chat "

else :

show
= " dnd "

self.changePresence(show)

if grinder.statistics.forLastTest.time < 5000 :

grinder.sleep(
5000 - grinder.statistics.forLastTest.time)

for j in range( 5 ):

self.sendMessage(message, self.targetUser)

if grinder.statistics.forLastTest.time < 5000 :

grinder.sleep(
5000 - grinder.statistics.forLastTest.time)



self.terminate()



def getXMLcontent(result):

parser
= DOMParser()

parser.reset()

parser.parse(InputSource(result.inputStream))

root
= parser.getDocument().getDocumentElement()



return root



def instrumentMethod(test, method_name, c = TestRunner):

""" Instrument a method with the given Test. """

unadorned
= getattr(c, method_name)

import new

method
= new.instancemethod(test.wrap(unadorned), None, c)

setattr(c, method_name, method)



# Replace each method with an instrumented version.

# You can call the unadorned method using self.getSession.__target__().

instrumentMethod(Test(
100 , ' Initiate a BOSH session ' ), ' initSession ' )

instrumentMethod(Test(
200 , ' Authenticate ' ), ' auth ' )

instrumentMethod(Test(
300 , ' Bind resource ' ), ' bind ' )

instrumentMethod(Test(
400 , ' Request a session from the server ' ), ' requestSession ' )

instrumentMethod(Test(
500 , ' Get roster ' ), ' getRoster ' )

instrumentMethod(Test(
600 , ' Change presence ' ), ' changePresence ' )

instrumentMethod(Test(
700 , ' Send one to one message ' ), ' sendMessage ' )

instrumentMethod(Test(
800 , ' Make an empty request to the server ' ), ' poll ' )

instrumentMethod(Test(
900 , ' Terminate the session ' ), ' terminate ' )

 

 

2.修改grinder.properties文件

 

 

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
# 每个agent启动10个进程
grinder.processes = 10
# 每个进程启动100个线程.

grinder.threads
= 100
# A Python object is callable if it defines a __call__ method. Each worker thread performs a number of runs of the test script, as configured by the property #grinder.runs. For each run, the worker thread calls its TestRunner; thus the __call__ method can be thought of as the definition of a run.

grinder.runs
= 1



# grinder.processIncrement=1

# grinder.processIncrementInterval=10000

# grinder.initialProcesses=1



# grinder.useConsole=false

grinder.consoleHost
= 172.0 . 7.206

grinder.consolePort
= 6372



grinder.logDirectory
= .. / logs

grinder.numberOfOldLogs
= 0



# grinder.initialSleepTime=500

# grinder.sleepTimeFactor=0.01

# grinder.sleepTimeVariation=0.005



grinder.jvm.arguments
=- Dpython.cachedir = .. / tmp



grinder.script
= .. / tests / one2one.py

 

3.启动./startConsole.sh

4.启动./startAgent.sh 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值