原始需求
一个客服GM能够加所有游戏服内的玩家为好友,并能进行聊天。具体功能如下:
* GM上、下线
* 加游戏玩家为好友
* 删游戏玩家为好友
* GM发送聊天消息
* 玩家推送聊天消息
额外限定:一个GM账号能够添加多个游戏玩家为好友,而一个游戏玩家只能被一个GM账号添加
需求分析
因为我们游戏内并没有跨服聊天、跨服好友这种功能,而且以后也不会支持,所以让GM在游戏里面创建角色,然后加各个游戏服的玩家进行聊天的方案是无法实施的。 而且GM实际上并不是一个游戏角色,也不用在游戏内创建。
整个的难点是,如何让各个游戏服访问到GM发过来的各种数据,如何将玩家的数据推送给GM。
具体实现
为了实现GM的数据在各个服务器传递,我们采用了一种简单的方案:将GM的数据放在我们的web服务器上,各个游戏服定时从web服务器去拿数据。
这种方案很简单,web服务器与游戏服不用长连接,直接用http的get和post方法就可以拿数据了。整个架构如下:
<code><span>GM1</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>运维聊天服</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>游戏web服务器</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>游戏服务器1</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>-</span><span>游戏客户端1</span><span>|</span><span>|</span><span>|</span><span>|</span><span>|</span><span>|</span><span>GM2</span><span>游戏服务器2</span><span>游戏客户端2</span></code>
这里客服GM1和GM2都用的web界面与游戏客户端聊天。
运维聊天服存在是因为:
* GM的创建需要运维那边的审批。。
* 游戏的web服务器可以进行白名单审查,只有运维聊天服的ip可以访问游戏的web服务器
上图中只有游戏客户端与游戏服务器是采用的tcp长连接,其他都是使用http短连接来实现。
web服务器采用的是nginx,而不是nodejs。nginx方案挺成熟的,而且部署也很容易。
由于,我对python的熟悉程度比lua程度高很多,所以用了uwsgi来做代理,而不是直接用lua来写。
而数据库则采用的redis,redis设置了定时存盘了。数据格式设置可参考我之前提的文章,基本都是 gm:%d:name
这种格式,key表示gmx的名字是什么,val表示名字。
实现代码
nginx和uwsgi的配置已略去。因为隐私原因,相关IP已略去,代码里面也有足够的注释,不再赘述:
<code><span>#encoding: utf-8</span><span>""" 新功能: * GM注册 * GM上线 * GM下线 * 加游戏玩家为好友 * 删除游戏好友 * GM推聊天信息 * 玩家推聊天信息 --- 消息数据格式为utf-8处理后的base64编码:游戏服和GM发过来的都是base64格式,要注意分隔符没做base64处理 GS只能用get方式推送消息,所以参数用类似于urllib quote(urlencode)进行了封装。运维客户端也用get 一个GM账号能添加多个游戏玩家为好友,而一个游戏玩家只能被一个GM账号添加 """</span><span>from</span> config <span>import</span> * <span>from</span> json <span>import</span> dumps, loads <span>import</span> base64 <span>import</span> urllib <span>import</span> urllib2 <span>import</span> copy <span>import</span> redis MSG_SEPARATOR = <span>","</span><span>#分割信息</span> MAX_RECV_AMOUNT = <span>10</span><span>#每次消息10条吧</span> MSG_MAX_LEN = <span>500</span><span>#消息不弄太长了</span>CONTENT_TYPE = [(<span>"Content-Type"</span>,<span>"text/html"</span>)] HTTP_STATUS = { <span>200</span>: <span>"200 OK"</span>, <span>404</span>: <span>"404 Not Found"</span>, } GAME_SERVER_INFO_URL = <span>"http://xxxxxyyyyy"</span>ROLE_INFO_URL = <span>"http://xxyyy?uid=%s&hostnum=%s"</span>red = redis.StrictRedis(host=REDIS.HOST, port=REDIS.PORT, db=REDIS.DB) <span>#游戏服务器IP白名单</span><span>if</span><span>not</span> globals().has_key(<span>"gServerIP"</span>): gServerIP = {} res_data = urllib2.urlopen(GAME_SERVER_INFO_URL) res = res_data.read() res_list = res.split(<span>"\n"</span>) <span>for</span> val <span>in</span> res_list: <span>if</span><span>not</span> val: <span>continue</span> _, port, ip, _ = val.split(<span>" "</span>) gServerIP[ip] = port gGMIP = { <span>"xxxxyyyy"</span> : <span>1</span>, } <span><span>def</span><span>is_gm_account_exist</span><span>(account_id)</span>:</span><span>if</span> red.get(<span>"gm_account:%s:name"</span> % account_id): <span>return</span><span>1</span><span>return</span><span>0</span><span><span>def</span><span>is_inter_server</span><span>(hostnum)</span>:</span><span>if</span> ( int(hostnum) >= <span>1000</span> ): <span>return</span><span>0</span><span>return</span><span>1</span><span><span>def</span><span>check_is_int</span><span>(account_id)</span>:</span><span>try</span>: int(account_id) <span>except</span>: <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: -<span>1</span>}) <span>return</span> () <span>#gm client ensures the id is unique</span><span><span>def</span><span>gm_create_account</span><span>(env, params)</span>:</span> account_id, account_name = params[<span>"gm_account"</span>], urllib.unquote(params[<span>"gm_name"</span>]) check_res = check_is_int(account_id) <span>if</span> check_res: <span>return</span> check_res <span>if</span> is_gm_account_exist(account_id): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>1</span>}) <span>#1 the role exists</span> red.set(<span>"gm_account:%s:name"</span> % account_id, account_name) red.sadd(<span>"gm_online_list"</span>, account_id) <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>}) <span>#check param</span><span><span>def</span><span>gm_add_friend</span><span>(env, params)</span>:</span> var = gm_account, hostnum, usernum = params[<span>"gm_account"</span>], params[<span>"host"</span>], params[<span>"uid"</span>] <span>for</span> num <span>in</span> var: check_res = check_is_int(num) <span>if</span> check_res: <span>return</span> check_res <span>if</span><span>not</span> is_gm_account_exist(gm_account): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>2</span>}) <span>#2 the role doesn't exist</span><span>if</span> ( red.get(<span>"gs_usernum:%s:friend"</span> % usernum) ): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>3</span>}) <span>#3 the usernum has gotten a friend</span><span>#内服计费没存数据,就不处理了</span><span>if</span><span>not</span> is_inter_server(hostnum): http_res_data = urllib2.urlopen(ROLE_INFO_URL % (usernum, hostnum)) res = loads(http_res_data.read()) <span>if</span> (type(res) != type({})) <span>or</span> (res.get(<span>"code"</span>, <span>0</span>) != <span>1</span>): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>4</span>}) <span>#4 the uid doesn't exist</span> red.sadd(<span>"gm_account:%s:friend"</span> % gm_account, usernum) <span>#两边都处理下</span> red.sadd(<span>"gs_hostnum:%s"</span> % hostnum, usernum) <span>#记录该服务器的所有玩家</span> red.set(<span>"gs_usernum:%s:hostnum"</span> % usernum, hostnum) <span>#该玩家的信息</span> red.set(<span>"gs_usernum:%s:friend"</span> % usernum, gm_account) <span>#一个玩家只能被一个gm添加为好友</span> red.sadd(<span>"apply_frd_list"</span>, usernum) <span>#usernum will be added </span> red.hdel(<span>"remove_frd_list"</span>, usernum) <span>#信息残留</span><span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>}) <span><span>def</span><span>gm_remove_friend</span><span>(env, params)</span>:</span> account_id, uid = params[<span>"gm_account"</span>], params[<span>"uid"</span>] <span>if</span><span>not</span> is_gm_account_exist(account_id): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>2</span>}) <span>#2 the role doesn't exist</span><span>if</span> red.get(<span>"gs_usernum:%s:friend"</span> % uid) != account_id: <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>5</span>}) <span># the usernum has friend but isn't the gm</span><span>if</span><span>not</span> red.srem(<span>"gm_account:%s:friend"</span> % account_id, uid): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>4</span>}) <span># the usernum is not a friend of the gm</span> hostnum = red.get(<span>"gs_usernum:%s:hostnum"</span> % uid) red.delete(<span>"gs_usernum:%s:hostnum"</span> % uid) <span>#合服考虑,如果合服了GM手动删除这个玩家吧</span> red.srem(<span>"gs_hostnum:%s"</span> % hostnum, uid) red.delete(<span>"gs_usernum:%s:friend"</span> % uid) red.hset(<span>"remove_frd_list"</span>, uid, hostnum) <span>#uid的信息已经丢失,先额外保存下hostnum信息</span> red.srem(<span>"apply_frd_list"</span>, uid) <span>#信息残留</span><span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>}) <span>#GM账号很少</span><span><span>def</span><span>gm_online</span><span>(env, params)</span>:</span> account_id = params[<span>"gm_account"</span>] <span>#可能客户端bug没发下线,直接sadd吧</span><span>if</span><span>not</span> is_gm_account_exist(account_id): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>2</span>}) <span>#2 the role doesn't exist</span> red.sadd(<span>"gm_online_list"</span>, account_id) <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>}) <span><span>def</span><span>gm_offline</span><span>(env, params)</span>:</span> account_id = params[<span>"gm_account"</span>] <span>if</span><span>not</span> red.srem(<span>"gm_online_list"</span>, account_id): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>}) <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>}) <span>#存在usernum上,gs_msg和gm_msg</span><span><span>def</span><span>gm_sendmsg</span><span>(env, params)</span>:</span> account_id, uid, msg = params[<span>"gm_account"</span>], params[<span>"uid"</span>], urllib.unquote(params[<span>"msg"</span>]) <span>#只能向好友发</span><span>if</span><span>not</span> red.sismember(<span>"gm_account:%s:friend"</span> % account_id, uid): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>4</span>}) <span># the usernum is not a friend of the gm</span><span>if</span> red.get(<span>"gs_usernum:%s:friend"</span> % uid) != account_id: <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>5</span>}) <span># the usernum has friend but isn't the gm or doesn't have</span> red.lpush(<span>"gs_usernum:%s:msg_from_gm"</span> % uid, msg) red.sadd(<span>"gm_newmsg_list"</span>, uid) <span>#gs get msg from this set</span><span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>}) <span>#gm轮训所有的,他那边还有个服务器...</span><span>#{gm_account:{"uid": msg, "uid2": msg2}}</span><span><span>def</span><span>gm_receivemsg</span><span>(env, params)</span>:</span> user_set = copy.copy(red.smembers(<span>"gs_newmsg_list"</span>)) msg_data = {} <span>for</span> uid <span>in</span> user_set: gm_account = red.get(<span>"gs_usernum:%s:friend"</span> % uid) <span>if</span><span>not</span> gm_account: <span>#理论上是不会</span><span>continue</span> msg_list = pop_msg(uid, <span>"msg_from_gs"</span>) send_msg = MSG_SEPARATOR.join(msg_list) <span>if</span><span>not</span> send_msg: <span>continue</span><span>if</span><span>not</span> gm_account <span>in</span> msg_data: msg_data[gm_account] = [] msg_data[gm_account].append({<span>"uid"</span> : uid, <span>"msg"</span> : send_msg}) <span>#red.srem("gs_newmsg_list", uid)</span><span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>, <span>"data"</span>: base64.b64encode(dumps(msg_data))}) <span><span>def</span><span>pop_msg</span><span>(uid, msg_type)</span>:</span> msg_list = [] msg_key = <span>"gs_usernum:%s:%s"</span> % (uid, msg_type) msg_len = min(MAX_RECV_AMOUNT, red.llen(msg_key)) <span>for</span> i <span>in</span> xrange(msg_len): piece_msg = red.rpop(msg_key) msg_list.append(piece_msg) <span>return</span> msg_list <span>#---------------------GS----------------------</span><span>#apply and remove</span><span><span>def</span><span>get_frd_relation</span><span>(env, params)</span>:</span> host = params[<span>"host"</span>] apply_user_set = copy.copy(red.smembers(<span>"apply_frd_list"</span>)) apply_data = {} <span>#{"res":1 "data":base64({uid: gm_account})}</span><span>for</span> uid <span>in</span> apply_user_set: hostnum = red.get(<span>"gs_usernum:%s:hostnum"</span> % uid) <span>if</span> hostnum != host: <span>continue</span> account_id = red.get(<span>"gs_usernum:%s:friend"</span> % uid) <span>if</span><span>not</span> account_id: <span>#error </span><span>continue</span> apply_data[uid] = [account_id, red.get(<span>"gm_account:%s:name"</span> % account_id)] red.srem(<span>"apply_frd_list"</span>, uid) del_user_list = red.hkeys(<span>"remove_frd_list"</span>) remove_list = [] <span>for</span> uid <span>in</span> del_user_list: hostnum = red.hget(<span>"remove_frd_list"</span>, uid) <span>if</span> hostnum != host: <span>continue</span> remove_list.append(uid) red.hdel(<span>"remove_frd_list"</span>, uid) <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>, <span>"apply_data"</span>: base64.b64encode(dumps(apply_data)), <span>"remove_data"</span>: base64.b64encode(dumps(remove_list))}) <span><span>def</span><span>gs_sendmsg</span><span>(env, params)</span>:</span> uid, msg = params[<span>"uid"</span>], urllib.unquote(params[<span>"msg"</span>]) <span>if</span><span>not</span> red.get(<span>"gs_usernum:%s:friend"</span> % uid): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>0</span>, <span>"errno"</span>: <span>5</span>}) <span># the usernum has friend but isn't the gm or doesn't have</span> red.lpush(<span>"gs_usernum:%s:msg_from_gs"</span> % uid, msg) red.sadd(<span>"gs_newmsg_list"</span>, uid) <span>#gm get msg from this set</span><span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>}) <span><span>def</span><span>gs_receivemsg</span><span>(env, params)</span>:</span> host = params[<span>"host"</span>] user_set = copy.copy(red.smembers(<span>"gm_newmsg_list"</span>)) total_msg_list = [] <span>for</span> uid <span>in</span> user_set: hostnum = red.get(<span>"gs_usernum:%s:hostnum"</span> % uid) <span>if</span> hostnum != host: <span>continue</span> msg_list = pop_msg(uid, <span>"msg_from_gm"</span>) user_msg = MSG_SEPARATOR.join(msg_list) <span>if</span><span>not</span> user_msg: <span>continue</span> msg_data = { <span>"uid"</span> : uid, <span>"msg"</span> : user_msg, } total_msg_list.append(msg_data) <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>, <span>"data"</span>: base64.b64encode(dumps(total_msg_list))}) <span><span>def</span><span>get_online_list</span><span>(env, params)</span>:</span> host = params[<span>"host"</span>] send_list = [] online_list = red.smembers(<span>"gm_online_list"</span>) <span>for</span> account_id <span>in</span> online_list: frd_set = red.smembers(<span>"gm_account:%s:friend"</span> % account_id) <span>for</span> uid <span>in</span> frd_set: <span>if</span> red.get(<span>"gs_usernum:%s:hostnum"</span> % uid) == host: send_list.append(account_id) <span>#只有这个服务器有gm的好友,才通知</span><span>break</span><span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, dumps({<span>"res"</span>: <span>1</span>, <span>"data"</span>: base64.b64encode(dumps(send_list))}) <span>#get: action=create&gm_account&gm_name 创建账号</span><span>#get: action=add&gm_account&host&uid 添加好友</span><span>#get: action=del&gm_account&uid 删除好友</span><span>#get: action=online&gm_account上线</span><span>#get: action=offline&gm_account 下线</span><span>#get: action=send&gm_account&uid&msg 发送消息</span><span>#get: action=receive 轮训消息</span> GM_FUNC = { <span>"create"</span> : gm_create_account, <span>"add"</span> : gm_add_friend, <span>"del"</span> : gm_remove_friend, <span>"online"</span> : gm_online, <span>"offline"</span> : gm_offline, <span>"send"</span> : gm_sendmsg, <span>"receive"</span> : gm_receivemsg, } <span><span>def</span><span>handle_gm_ticket</span><span>(env, params)</span>:</span><span>if</span><span>not</span> gGMIP.get(env[<span>"REMOTE_ADDR"</span>], <span>0</span>): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, <span>"%s has no access to the website"</span> % env[<span>"REMOTE_ADDR"</span>] func = GM_FUNC.get(params[<span>"action"</span>], <span>None</span>) <span>if</span><span>not</span> func: <span>return</span> HTTP_STATUS[<span>404</span>], CONTENT_TYPE, <span>"err action %s"</span> % params[<span>"action"</span>] <span>return</span> func(env, params) <span>#get action=relation&host</span><span>#get action=send&uid&msg</span><span>#get action=receive&host</span><span>#get action=online&host </span> GS_FUNC = { <span>"relation"</span> : get_frd_relation, <span>"send"</span> : gs_sendmsg, <span>"receive"</span> : gs_receivemsg, <span>"online"</span> : get_online_list, } <span><span>def</span><span>handle_gs_ticket</span><span>(env, params)</span>:</span><span>if</span><span>not</span> gServerIP.get(env[<span>"REMOTE_ADDR"</span>], <span>0</span>): <span>return</span> HTTP_STATUS[<span>200</span>], CONTENT_TYPE, <span>"%s has no access to the website"</span> % env[<span>"REMOTE_ADDR"</span>] func = GS_FUNC.get(params[<span>"action"</span>], <span>None</span>) <span>if</span><span>not</span> func: <span>return</span> HTTP_STATUS[<span>404</span>], CONTENT_TYPE, <span>"err action %s"</span> % params[<span>"action"</span>] <span>return</span> func(env, params) </code>
版权声明:本文为博主原创文章,未经博主允许不得转载。
以上就介绍了用nginx+uwsgi+redis实现游戏GM聊天功能,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

PHP terutamanya pengaturcaraan prosedur, tetapi juga menyokong pengaturcaraan berorientasikan objek (OOP); Python menyokong pelbagai paradigma, termasuk pengaturcaraan OOP, fungsional dan prosedur. PHP sesuai untuk pembangunan web, dan Python sesuai untuk pelbagai aplikasi seperti analisis data dan pembelajaran mesin.

PHP berasal pada tahun 1994 dan dibangunkan oleh Rasmuslerdorf. Ia pada asalnya digunakan untuk mengesan pelawat laman web dan secara beransur-ansur berkembang menjadi bahasa skrip sisi pelayan dan digunakan secara meluas dalam pembangunan web. Python telah dibangunkan oleh Guidovan Rossum pada akhir 1980 -an dan pertama kali dikeluarkan pada tahun 1991. Ia menekankan kebolehbacaan dan kesederhanaan kod, dan sesuai untuk pengkomputeran saintifik, analisis data dan bidang lain.

PHP sesuai untuk pembangunan web dan prototaip pesat, dan Python sesuai untuk sains data dan pembelajaran mesin. 1.Php digunakan untuk pembangunan web dinamik, dengan sintaks mudah dan sesuai untuk pembangunan pesat. 2. Python mempunyai sintaks ringkas, sesuai untuk pelbagai bidang, dan mempunyai ekosistem perpustakaan yang kuat.

PHP tetap penting dalam proses pemodenan kerana ia menyokong sejumlah besar laman web dan aplikasi dan menyesuaikan diri dengan keperluan pembangunan melalui rangka kerja. 1.Php7 meningkatkan prestasi dan memperkenalkan ciri -ciri baru. 2. Rangka kerja moden seperti Laravel, Symfony dan CodeIgniter memudahkan pembangunan dan meningkatkan kualiti kod. 3. Pengoptimuman prestasi dan amalan terbaik terus meningkatkan kecekapan aplikasi.

Phphassignificantelympactedwebdevelopmentandextendsbeyondit.1) itpowersmajorplatformslikeworderpressandexcelsindatabaseIntions.2) php'SadaptabilityAldoStoScaleforlargeapplicationFrameworksLikelara.3)

Jenis PHP meminta untuk meningkatkan kualiti kod dan kebolehbacaan. 1) Petua Jenis Skalar: Oleh kerana Php7.0, jenis data asas dibenarkan untuk ditentukan dalam parameter fungsi, seperti INT, Float, dan lain -lain. 2) Return Type Prompt: Pastikan konsistensi jenis nilai pulangan fungsi. 3) Jenis Kesatuan Prompt: Oleh kerana Php8.0, pelbagai jenis dibenarkan untuk ditentukan dalam parameter fungsi atau nilai pulangan. 4) Prompt jenis yang boleh dibatalkan: membolehkan untuk memasukkan nilai null dan mengendalikan fungsi yang boleh mengembalikan nilai null.

Dalam PHP, gunakan kata kunci klon untuk membuat salinan objek dan menyesuaikan tingkah laku pengklonan melalui kaedah Magic \ _ _ _. 1. Gunakan kata kunci klon untuk membuat salinan cetek, mengkloning sifat objek tetapi bukan sifat objek. 2. Kaedah klon \ _ \ _ boleh menyalin objek bersarang untuk mengelakkan masalah menyalin cetek. 3. Beri perhatian untuk mengelakkan rujukan pekeliling dan masalah prestasi dalam pengklonan, dan mengoptimumkan operasi pengklonan untuk meningkatkan kecekapan.

PHP sesuai untuk pembangunan web dan sistem pengurusan kandungan, dan Python sesuai untuk sains data, pembelajaran mesin dan skrip automasi. 1.PHP berfungsi dengan baik dalam membina laman web dan aplikasi yang cepat dan berskala dan biasanya digunakan dalam CMS seperti WordPress. 2. Python telah melakukan yang luar biasa dalam bidang sains data dan pembelajaran mesin, dengan perpustakaan yang kaya seperti numpy dan tensorflow.


Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Versi Mac WebStorm
Alat pembangunan JavaScript yang berguna

Dreamweaver CS6
Alat pembangunan web visual

Muat turun versi mac editor Atom
Editor sumber terbuka yang paling popular

DVWA
Damn Vulnerable Web App (DVWA) ialah aplikasi web PHP/MySQL yang sangat terdedah. Matlamat utamanya adalah untuk menjadi bantuan bagi profesional keselamatan untuk menguji kemahiran dan alatan mereka dalam persekitaran undang-undang, untuk membantu pembangun web lebih memahami proses mengamankan aplikasi web, dan untuk membantu guru/pelajar mengajar/belajar dalam persekitaran bilik darjah Aplikasi web keselamatan. Matlamat DVWA adalah untuk mempraktikkan beberapa kelemahan web yang paling biasa melalui antara muka yang mudah dan mudah, dengan pelbagai tahap kesukaran. Sila ambil perhatian bahawa perisian ini

Pelayar Peperiksaan Selamat
Pelayar Peperiksaan Selamat ialah persekitaran pelayar selamat untuk mengambil peperiksaan dalam talian dengan selamat. Perisian ini menukar mana-mana komputer menjadi stesen kerja yang selamat. Ia mengawal akses kepada mana-mana utiliti dan menghalang pelajar daripada menggunakan sumber yang tidak dibenarkan.