一、前言

最近,需要接触区块链项目的主链开发,在EOSBTCethereum超级账本这几种区块链技术当中,相互对比后,最终还是以go-ethereum为解决方案。

ethereum为基准去找解决方案,最终找到了2个符合自己要求的方案,分别如下:美图gttc。本来是想用gttc的这个解决方案的,但是它是基于go-ethereum最新源码来进行二次开发的,相对不稳定,因此还是用美图的解决方案了,毕竟这公司大一点,没那么多坑。

二、源码

为了方便测试,我们需要将节点最大验证器数修改一下,这样便于我们进行简单测试

修改consensus/dpos/dpos.go文件的maxValidator

// 新值
maxValidatorSize = 21
// 旧值
maxValidatorSize = 3

三、构建

# 进入源码根目录
docker build . -t meitugeth

注意:构建过程中会用到build\env.sh文件,会提示无权限,因此你需要给该文件赋予执行权限。

sudo chmod 777 build\env.sh

四、部署

1. 创建节点数据目录

最好事先创建好相应的目录,否则运行后,动态创建目录,会有权限的问题,当然也可以通过命令进行设置目录的权限。

mkdir ~/data
mkdir ~/data/meitu
mkdir ~/data/meitu/node1
mkdir ~/data/meitu/node2
mkdir ~/data/meitu/node3

2. 编写docker-compose.yml文件

version: '3'
services:
meitu_node_1:
image: meitugeth
container_name: meitu_node_1
build:
context: .
command: --ipcpath "/root/.ethereum/geth.ipc" --port 30303
ports:
- 15450:8545
- 15460:8546
- 10303:30303
- 10303:30303/udp
- 10304:30304/udp
volumes:
- /etc/localtime:/etc/localtime
- ~/data/meitu/node1/:/root/.ethereum/
environment:
TZ: Asia/Shanghai meitu_node_2:
image: meitugeth
container_name: meitu_node_2
build:
context: .
command: --ipcpath "/root/.ethereum/geth.ipc" --port 30303
depends_on:
- meitu_node_1
ports:
- 25450:8545
- 25460:8546
- 20303:30303
- 20303:30303/udp
- 20304:30304/udp
volumes:
- /etc/localtime:/etc/localtime
- ~/data/meitu/node2/:/root/.ethereum/
environment:
TZ: Asia/Shanghai meitu_node_3:
image: meitugeth
container_name: meitu_node_3
build:
context: .
command: --ipcpath "/root/.ethereum/geth.ipc" --port 30303
depends_on:
- meitu_node_1
ports:
- 45450:8545
- 45460:8546
- 40303:30303
- 40303:30303/udp
- 40304:30304/udp
volumes:
- /etc/localtime:/etc/localtime
- ~/data/meitu/node3/:/root/.ethereum/
environment:
TZ: Asia/Shanghai

3. 启动节点

在根目录下启动3个以太坊节点

docker-compose up --build -d

4. 启动思路

美图以太坊这块有2种启动网络:

  • 在创世块里配置好第一验证节点,然后启动
  • 混合POW和DPOS,用POW进行投票,产生第一批验证节点,并自动切换到DPOS

5. 首次启动

1. 进入容器

进入容器命令如下:

# 模板
docker exec -it [容器名|容器ID] /bin/sh
# 例子
docker exec -it meitu_node_1 /bin/sh
docker exec -it meitu_node_2 /bin/sh
docker exec -it meitu_node_3 /bin/sh

2. 进入geth JavaScript控制台

# 方式一
geth attach ipc:/root/.ethereum/geth.ipc
# 方式二
docker exec -it meitu_node_1 geth attach ipc:/root/.ethereum/geth.ipc
# 方式三:使用别名
alias geth="docker exec -it meitu_node_1 geth attach ipc:/root/.ethereum/geth.ipc"

3. 创建账户

进入geth JavaScript 控制台后,需哟啊创建账户,命令如下;

# 模板
personal.newAccount('名称')
# 例子
personal.newAccount('test001')
"0x849f9442198282fb21539351edb0378463e4c251"
personal.newAccount('test002')
"0x2c08f54d5b324c0175ea53b997f5ce1f61a7e4ed"
personal.newAccount('test003')
"0xc4118320f3d3c37a2ca8dad5c2f2a40f2a23ba02"

创建成功后,需要将返回的地址记录起来

loop:重复1-3步骤,在node1、node2、node3分别创建账户

4. 编写创世块配置文件

将上一步操作生成的地址写入到创世块文件中,三个节点的地址分别为:

0x849f9442198282fb21539351edb0378463e4c251
0x2c08f54d5b324c0175ea53b997f5ce1f61a7e4ed
0xc4118320f3d3c37a2ca8dad5c2f2a40f2a23ba02

将3个节点地址列入第一批验证人列表

{
"config": {
"chainId": 7777,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock":0,
"dpos":{
"validators":[
"0x849f9442198282fb21539351edb0378463e4c251",
"0x2c08f54d5b324c0175ea53b997f5ce1f61a7e4ed",
"0xc4118320f3d3c37a2ca8dad5c2f2a40f2a23ba02"
]
}
},
"nonce": "0x0000000000000042",
"difficulty": "0x020000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x500000",
"alloc": {}
}

创世配置参数说明:

  • nonce:64位随机数,用于挖矿
  • timestamp:创世块的时间戳
  • parentHash:上一个区块的hash值,因为是创世块,所以这个值是0
  • mixHash:与nonce配合用于挖矿,由上一个区块的一部分生成hash
  • extraData:附加信息,任意填写
  • gasLimit:对GAS的消耗总量限制,用来限制区块能包含的交易信息总和
  • difficulty:难度值,越大越难
  • coinbase:矿工账号,第一个区块挖出后将给这个矿工账号发送奖励的以太币
  • alloc:预设账号以及账号的以太币数量,测试链挖矿比较容易可以不配置
  • chainId:指定了独立的区块链网络ID,不同ID网络的节点无法互相连接

5. 初始化创世目录

1. 删除每个节点下geth目录,保留keystore

移除geth目录,便于移除旧的无效数据,因为节点刚启动的时候,使用的是默认创世配置,而自定义的又不一样,因此需要移除。

sudo rm -rf ~/data/meitu/node1/geth
sudo rm -rf ~/data/meitu/node2/geth
sudo rm -rf ~/data/meitu/node3/geth

2. 拷贝创世配置到数据目录

将创世配置拷贝到数据目录中,便于容器内能访问,至于这个目录跟docker-compose.yml映射的目录有关。

因此,命令也要相应的变更。

cp genesis.json ~/data/meitu/node1
cp genesis.json ~/data/meitu/node2
cp genesis.json ~/data/meitu/node3

3. 初始化创世配置

进入容器,并执行初始化命令。

# 节点1
docker exec -it meitu_node_1 /bin/sh
geth init /root/.ethereum/genesis.json
# 节点2
docker exec -it meitu_node_2 /bin/sh
geth init /root/.ethereum/genesis.json
# 节点3
docker exec -it meitu_node_3 /bin/sh
geth init /root/.ethereum/genesis.json

**loop:重复在node2、node3上分别执行init

6. 重启节点网络

以下命令需要在docker-compose.yml文件的当前目录方可运行。

# 移除容器
docker-compose down
# 启动容器
docker-compose up -d

7. 查看验证人是否设置成功

1. 进入容器

docker exec -it meitu_node_3 /bin/sh

2. 进入geth JavaScript控制台

geth attach ipc:/root/.ethereum/geth.ipc

3. 执行获取验证人列表命令

dpos.getValidators()
["0x849f9442198282fb21539351edb0378463e4c251", "0x2c08f54d5b324c0175ea53b997f5ce1f61a7e4ed", "0xc4118320f3d3c37a2ca8dad5c2f2a40f2a23ba02"]

8. 节点互联

1. 查看节点是否互联

admin.peers
[]

返回的数据为[],说明节点之间没有互相发现。

2. 设置节点互联

1. 查看每个节点信息
admin.nodeInfo

确认:enode都不一样,protocols都一样。

记下三个enode

"enode://7f2f1a5818b4bb7e756036ab08834386534807bbf5c5a305ddcbefa1ff9ea99028feb00cb78322ac39340501d5b7c6147e169aadbb028daf20f8d73dbdfea98e@[::]:30303"
"enode://6ab4f74058b9c1e43d2d0c6f55f538ea7f2f366dd9f8f560024f14603333f017d3404b9c9711538289fa76504fecf33cf0e36cce7b0414604f673abe93012413@[::]:30303"
"enode://e82fecab04e5e902a9e4ea491527ea958d2cdeb83383dfa36562e32a51eedb204a541e00ef0b497704ec0e91017799a73283e53f6dffdeef492a4230626b10b6@[::]:30303"
2. 查看docker容器网络信息
# 显示docker所有网络信息
docker network ls
# 查看具体网络信息
docker network inspect [网络名称]
# 例子
docker network inspect docker_default

执行查看网络信息命令后,会返回一下内容

[
{
"Name": "docker_default",
"Id": "984fabf7e51b07c1984114720f98f305cc61cc26546cf9da4bcbbbc36a591351",
"Created": "2018-12-05T06:06:13.435067024Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"263f1553108cc8ea00b76598adb6d66649287943c7d0f50d0be02963863ff45c": {
"Name": "meitu_node_2",
"EndpointID": "9f4114a81133bd490b501ac45fd50fe512309f9096b5468054bd074bad45a07d",
"MacAddress": "02:42:ac:14:00:03",
"IPv4Address": "172.20.0.3/16",
"IPv6Address": ""
},
"3acd943c8e0759dc241d7cc623b1a1ca45096480dcd2fd0daa8b951407eb40bf": {
"Name": "meitu_node_3",
"EndpointID": "0480296c4e8217862358143a084da2d1563cd4f60105e6020434f222320681a5",
"MacAddress": "02:42:ac:14:00:04",
"IPv4Address": "172.20.0.4/16",
"IPv6Address": ""
},
"416fe5eb074c24f032d5bd49a6be68cf293a30af17780133b9fa63663e4b7097": {
"Name": "meitu_node_1",
"EndpointID": "0dc00e9c6f63f844502525b34e87baf62f4de852ac46907951d4b689dd89635f",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
"com.docker.compose.network": "default",
"com.docker.compose.project": "docker",
"com.docker.compose.version": "1.23.1"
}
}
]

找到不同容器中,相应的IP地址。

记录下每个节点的IP,也可以用127.0.0.1加节点映射到本机的不同网络端口。

meitu_node_1 172.20.0.2
meitu_node_2 172.20.0.3
meitu_node_3 172.20.0.4
3. 添加监视器

进入节点1 geth JavaScript 控制台后,执行以下命令:

# 添加节点2的监视器
admin.addPeer("enode://6ab4f74058b9c1e43d2d0c6f55f538ea7f2f366dd9f8f560024f14603333f017d3404b9c9711538289fa76504fecf33cf0e36cce7b0414604f673abe93012413@[172.20.0.3]:30303")
# 添加节点3的监视器
admin.addPeer("enode://e82fecab04e5e902a9e4ea491527ea958d2cdeb83383dfa36562e32a51eedb204a541e00ef0b497704ec0e91017799a73283e53f6dffdeef492a4230626b10b6@[172.20.0.4]:30303")
4.查看节点网络

在执行完添加监视器后,执行admin.peers即可看到节点已经互联起来。

admin.peers
[{
caps: ["eth/62", "eth/63"],
id: "6ab4f74058b9c1e43d2d0c6f55f538ea7f2f366dd9f8f560024f14603333f017d3404b9c9711538289fa76504fecf33cf0e36cce7b0414604f673abe93012413",
name: "Geth/v1.7.4-stable-a487fc95/linux-amd64/go1.9.7",
network: {
localAddress: "172.20.0.2:60018",
remoteAddress: "172.20.0.3:30303"
},
protocols: {
eth: {
difficulty: 131189,
head: "0xa00badd4041033da53c0a34cce5aa59885d7f638e00e1e307b04c02ee640df19",
version: 63
}
}
}, {
caps: ["eth/62", "eth/63"],
id: "e82fecab04e5e902a9e4ea491527ea958d2cdeb83383dfa36562e32a51eedb204a541e00ef0b497704ec0e91017799a73283e53f6dffdeef492a4230626b10b6",
name: "Geth/v1.7.4-stable-a487fc95/linux-amd64/go1.9.7",
network: {
localAddress: "172.20.0.2:36700",
remoteAddress: "172.20.0.4:30303"
},
protocols: {
eth: {
difficulty: 131076,
head: "0xe30ff3a8d1ae16384369c45d106841ef44e83c12eae2e2c66dce1bdccc9ba4d6",
version: 63
}
}
}]

注意:这一步完成了,仅仅是临时的,每次重启docker之后admin.peers会重新为空。

9. 配置永久互联

临时互联不方便,可以将bootnodes配置到启动文件中。

修改docker-compose.yml文件,将节点1的连接配置进去。

version: '3'
services:
meitu_node_1:
image: meitugeth
container_name: meitu_node_1
build:
context: ..
command: --ipcpath "/root/.ethereum/geth.ipc" --port 30303
ports:
- 15450:8545
- 15460:8546
- 10303:30303
- 10303:30303/udp
- 10304:30304/udp
volumes:
- /etc/localtime:/etc/localtime
- ~/data/meitu/node1/:/root/.ethereum/
environment:
TZ: Asia/Shanghai meitu_node_2:
image: meitugeth
container_name: meitu_node_2
build:
context: ..
command: --ipcpath "/root/.ethereum/geth.ipc" --port 30303 --bootnodes enode://7f2f1a5818b4bb7e756036ab08834386534807bbf5c5a305ddcbefa1ff9ea99028feb00cb78322ac39340501d5b7c6147e169aadbb028daf20f8d73dbdfea98e@[172.20.0.2]:30303
depends_on:
- meitu_node_1
ports:
- 25450:8545
- 25460:8546
- 20303:30303
- 20303:30303/udp
- 20304:30304/udp
volumes:
- /etc/localtime:/etc/localtime
- ~/data/meitu/node2/:/root/.ethereum/
environment:
TZ: Asia/Shanghai meitu_node_3:
image: meitugeth
container_name: meitu_node_3
build:
context: ..
command: --ipcpath "/root/.ethereum/geth.ipc" --port 30303 --bootnodes enode://7f2f1a5818b4bb7e756036ab08834386534807bbf5c5a305ddcbefa1ff9ea99028feb00cb78322ac39340501d5b7c6147e169aadbb028daf20f8d73dbdfea98e@[172.20.0.2]:30303
depends_on:
- meitu_node_1
ports:
- 45450:8545
- 45460:8546
- 40303:30303
- 40303:30303/udp
- 40304:30304/udp
volumes:
- /etc/localtime:/etc/localtime
- ~/data/meitu/node3/:/root/.ethereum/
environment:
TZ: Asia/Shanghai

这个时候,“主网”启动成功了!!!

五、运行

1. 解锁账户

分别在3个节点上把validator无限期解锁,谁不解锁谁别出块、跳过你。

这里源码默认10秒1块。

进入geth JavaScript控制台后,执行以下命令:

# 模板
personal.unlockAccount(eth.validator,'名称',0)
# 例子
personal.unlockAccount(eth.validator,'jce001',0)
personal.unlockAccount(eth.validator,'jce002',0)
personal.unlockAccount(eth.validator,'jce003',0)

根据美图解释,这里validatorcoinbase的区别:

  • coinbase:收取挖矿奖励
  • validator:可以设置为其他地址,但默认和coinbase一样。

2. 启动挖矿

进入geth JavaScript控制台后,执行以下命令:

miner.start()

3. 获取区块信息

进入geth JavaScript控制台后,执行以下命令:

# 模板
eth.getBlock(区块编号)
# 例子
eth.getBlock(1)
# 结果
{
coinbase: "0x849f9442198282fb21539351edb0378463e4c251",
difficulty: 1,
extraData: "0xd783010704846765746887676f312e392e37856c696e7578000000000000000084c3b20f15eb99c19bb8567d3a27a52947efb816f647cbc4491540ee5de685d54f4126d236f031d33312dfab1a5d7a895bbd4d154afd366b30918a9af6868ab300",
gasLimit: 5237761,
gasUsed: 0,
hash: "0x30964585add8b4ef65529f38ebe00bb6581fc9ae7323327f7dfd666754de883b",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
nonce: "0x0000000000000000",
number: 1,
parentHash: "0x9390ffeae9812417704193667a0e106c8cd9e701217deb054737dab0325191d3",
receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 794,
stateRoot: "0xc5a87ecb7262f6c507f488f5f93efa27df81550f1e7691c1ab2093a4218d2ca0",
timestamp: 1543990290,
totalDifficulty: 131073,
transactions: [],
transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
uncles: [],
validator: "0x849f9442198282fb21539351edb0378463e4c251"
}

六、测试

1. 获取账户余额

# 获取账户
eth.accounts # 获取余额
eth.getBalance(账户地址) # 格式化长度
web3.fromWei(数值) # 获取格式化后的余额,默认取第一个账户
web3.fromWei(eth.getBalacne(eth.accounts[0])) # 获取指定账户余额
web3.fromWei(eth.getBalance("0x849f9442198282fb21539351edb0378463e4c251"))

2. 交易

# 模板
eth.sendTransaction({from: "发送者", to: "接受者", value: 数量})
# 例子
eth.sendTransaction({from: "0x849f9442198282fb21539351edb0378463e4c251", to: "0xc4118320f3d3c37a2ca8dad5c2f2a40f2a23ba02", value: 1000000000000000000})

通过获取余额判断是否转账成功,也可通过返回的交易编号查询情况。

web3.eth.getTransactionReceipt('0x8a4104da45c736c7a671ff7974b9b9a1848ff4c001f3cbcd4eb427aab50d604f')

七、参考

美图DPOS以太坊教程(Docker版)的更多相关文章

  1. docker 搭建以太坊私有链搭建

    最近区块链,火得不行,身边也有朋友准备玩这个,说是搭了一个星期,没有把环境搭建起来,叫我帮忙看看环境怎么搭建 于是我找到了官方的地址 https://github.com/ethereum/go-et ...

  2. 基于docker的以太坊集群的私有链开发环境

    转载博文:https://www.jianshu.com/p/8af386ec5f9e https://www.jianshu.com/p/7994db7a2b89?from=singlemessag ...

  3. 以太坊ERC20代币开发

    以太坊ERC20代币开发首先需要对以太坊,代币,ERC20,智能合约等以太坊代币开发中的基本概念有了解.根据我们的示例代码就可以发行自己的以太坊代币. 什么是ERC20 可以把ERC20简单理解成以太 ...

  4. 以太坊开发DApp实战教程——用区块链、星际文件系统(IPFS)、Node.js和MongoDB来构建电商平台(一)

    第一节 简介 欢迎和我们一起来用以太坊开发构建一个去中心化电商DApp!我们将用区块链.星际文件系统(IPFS).Node.js和MongoDB来构建电商平台类似淘宝的在线电商应用,卖家可以自由地出售 ...

  5. 区块链教程(二):比特币、区块链、以太坊、Hyperledger的关系

    不知道大家喜不喜欢音乐! 朋克音乐:诞生于七十年代中期,一种源于六十年代车库摇滚和前朋克摇滚的简单摇滚乐.它由一个简单悦耳的主旋律和三个和弦组成,经过演变,朋克已经逐渐脱离摇滚,成为一种独立的音乐,朋 ...

  6. Android-Android版美图秀秀

    Android版美图秀秀,主要是修改图片的显示效果,修改图片的透明的显示范围,修改图片的红色显示范围,修改图片绿色显示范围,修改图片蓝色显示范围: 想要修改图片的颜色就必须要重新绘制,一想到重新绘制就 ...

  7. 以太坊go-ethereum客户端docker安装(一)

    最近一段时间忙于工作,就没来得及发表博客,但一直没有停止对区块链的研究.周末抽时间分享一下近期比较重大的收获之一--使用docker来搭建和使用以太坊的节点.本人已经顺利搭建出,开发环境,测试环境,F ...

  8. 以太坊开发教程(二) 利用truffle发布宠物商店 DAPP 到 以太坊测试环境Ropsten

    1.环境安装 1) node安装 设置镜像地址: curl --silent --location https://rpm.nodesource.com/setup_8.x | bash -下载安装 ...

  9. 以太坊(ethereum)开发DApp应用的入门区块链技术教程

    概述 对初学者,首先要了解以太坊开发相关的基本概念.   学习以太坊开发的一般前序知识要求,最好对以下技术已经有一些基本了解: 一种面向对象的开发语言,例如:Python,Ruby,Java... 前 ...

随机推荐

  1. React VR 技术开发群 579149907

    React VR 技术开发群 579149907,欢迎加入讨论!分享经验!

  2. nginx配置文件 nginx.conf 说明

    #user nobody; #开启进程数 <=CPU数  worker_processes 1; #错误日志保存位置 #error_log logs/error.log; #error_log ...

  3. 高可用Hadoop平台-集成Hive HAProxy

    1.概述 这篇博客是接着<高可用Hadoop平台>系列讲,本篇博客是为后面用 Hive 来做数据统计做准备的,介绍如何在 Hadoop HA 平台下集成高可用的 Hive 工具,下面我打算 ...

  4. Java配置分离之Spring远程配置

    访问我的博客 前言 集群应用的配置文件如果写在项目的 resources 目录下面,当遇到需要修改某一个配置值时,需要将集群的所有应用的配置信息进行修改,并且将机密的配置信息比如数据库账号密码如果不进 ...

  5. 请读下面的这句绕口令:ResourceManager中的Resource Estimator框架介绍与算法剖析

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由宋超发表于云+社区专栏 本文首先介绍了Hadoop中的ResourceManager中的estimator service的框架与运行 ...

  6. Tomcat学习总结(10)——Tomcat多实例冗余部署

    昨天在跟群友做技术交流的时候,了解到,有很多大公司都是采用了高可用的,分布式的,实例沉余1+台.但是在小公司的同学也很多,他们反映并不是所有公司都有那样的资源来供你调度.往往公司只会给你一台机器,因为 ...

  7. (转)注解用法详解—@@SuppressWarnings

    一.前言 编码时我们总会发现如下变量未被使用的警告提示: 上述代码编译通过且可以运行,但每行前面的“感叹号”就严重阻碍了我们判断该行是否设置的断点了.这时我们可以在方法前添加 @SuppressWar ...

  8. PHP7最高性能优化建议

    PHP7已经发布了, 作为PHP10年来最大的版本升级, 最大的性能升级, PHP7在多放的测试中都表现出很明显的性能提升, 然而, 为了让它能发挥出最大的性能, 我还是有几件事想提醒下. PHP7 ...

  9. How to describe the wind sprial in computer system?

    How to describe the wind sprial in computer system? 2017-02-21 刘崇军 风螺旋线 If we want get the approval ...

  10. http Socket长连接

    文档:http://www.cocoachina.com/ios/20160602/16572.html socket(套接字)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元,包含进行网 ...