精华内容
下载资源
问答
  • keras的三种模型实现与区别说明

    千次阅读 2020-12-02 23:43:31
    一、keras提供了三种定义模型的方式 1. 序列式(Sequential) API 序贯(sequential)API允许你为大多数问题逐层堆叠创建模型。虽然说对很多应用来说,这样一个手法很简单也解决了很多深度学习网络结构的构建,但是...

    更多编程教程请到:菜鸟教程 https://www.piaodoo.com/

    友情链接:

    高州阳光论坛https://www.hnthzk.com/

    人人影视http://www.op-kg.com/

    前言

    一、keras提供了三种定义模型的方式

    1. 序列式(Sequential) API

    序贯(sequential)API允许你为大多数问题逐层堆叠创建模型。虽然说对很多的应用来说,这样的一个手法很简单也解决了很多深度学习网络结构的构建,但是它也有限制-它不允许你创建模型有共享层或有多个输入或输出的网络。

    2. 函数式(Functional) API

    Keras函数式(functional)API为构建网络模型提供了更为灵活的方式。

    它允许你定义多个输入或输出模型以及共享图层的模型。除此之外,它允许你定义动态(ad-hoc)的非周期性(acyclic)网络图。

    模型是通过创建层的实例(layer instances)并将它们直接相互连接成对来定义的,然后定义一个模型(model)来指定那些层是要作为这个模型的输入和输出。

    3.子类(Subclassing) API

    补充知识:keras pytorch 构建模型对比

    使用CIFAR10数据集,用三种框架构建Residual_Network作为例子,比较框架间的异同。

    数据集格式

    pytorch的数据集格式

    import torch
    import torch.nn as nn
    import torchvision
    

    Download and construct CIFAR-10 dataset.

    train_dataset = torchvision.datasets.CIFAR10(root=’…/…/data/’,
    train=True,
    download=True)

    Fetch one data pair (read data from disk).

    image, label = train_dataset[0]
    print (image.size()) # torch.Size([3, 32, 32])
    print (label) # 6
    print (train_dataset.data.shape) # (50000, 32, 32, 3)

    type(train_dataset.targets)==list

    print (len(train_dataset.targets)) # 50000

    Data loader (this provides queues and threads in a very simple way).

    train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
    batch_size=64,
    shuffle=True)
    “”"

    演示DataLoader返回的数据结构

    When iteration starts, queue and thread start to load data from files.

    data_iter = iter(train_loader)

    Mini-batch images and labels.

    images, labels = data_iter.next()
    print(images.shape) # torch.Size([100, 3, 32, 32])
    print(labels.shape)

    torch.Size([100]) 可见经过DataLoader后,labels由list变成了pytorch内置的tensor格式

    “”"

    一般使用的话是下面这种

    Actual usage of the data loader is as below.

    for images, labels in train_loader:

    Training code should be written here.

    pass

    keras的数据格式

    import keras
    from keras.datasets import cifar10
    

    (train_x, train_y) , (test_x, test_y) = cifar10.load_data()
    print(train_x.shape) # ndarray 类型: (50000, 32, 32, 3)
    print(train_y.shape) # (50000, 1)

    输入网络的数据格式不同

    """
    1: pytorch 都是内置torch.xxTensor输入网络,而keras的则是原生ndarray类型
    2: 对于multi-class的其中一种loss,即cross-entropy loss 而言,
      pytorch的api为 CorssEntropyLoss, 但y_true不能用one-hoe编码!这与keras,tensorflow	    都不同。tensorflow相应的api为softmax_cross_entropy
      他们的api都仅限于multi-class classification
    3*: 其实上面提到的api都属于categorical cross-entropy loss,
      又叫 softmax loss,是函数内部先进行了 softmax 激活,再经过cross-entropy loss。
      这个loss是cross-entropy loss的变种,
      cross-entropy loss又叫logistic loss 或 multinomial logistic loss。
      实现这种loss的函数不包括激活函数,需要自定义。
      pytorch对应的api为BCEloss(仅限于 binary classification),
      tensorflow 对应的api为 log_loss。
      cross-entropy loss的第二个变种是 binary cross-entropy loss 又叫 sigmoid cross-  entropy loss。
      函数内部先进行了sigmoid激活,再经过cross-entropy loss。
      pytorch对应的api为BCEWithLogitsLoss,
      tensorflow对应的api为sigmoid_cross_entropy
    """
    

    pytorch

    criterion = nn.CrossEntropyLoss()

    for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
    images = images.to(device)
    labels = labels.to(device)

    # Forward pass
    outputs = model(images)
    # 对于multi-class cross-entropy loss
    # 输入y_true不需要one-hot编码
    loss = criterion(outputs, labels)
    

    keras

    对于multi-class cross-entropy loss

    输入y_true需要one-hot编码

    train_y = keras.utils.to_categorical(train_y,10)

    model.fit_generator(datagen.flow(train_x, train_y, batch_size=128),
    validation_data=[test_x,test_y],
    epochs=epochs,steps_per_epoch=steps_per_epoch, verbose=1)

    整体流程

    keras 流程

    model = myModel()
    model.compile(optimizer=Adam(0.001),loss="categorical_crossentropy",metrics=["accuracy"])
    model.fit_generator(datagen.flow(train_x, train_y, batch_size=128),
              validation_data=[test_x,test_y],
              epochs=epochs,steps_per_epoch=steps_per_epoch, verbose=1, workers=4)
    #Evaluate the accuracy of the test dataset
    accuracy = model.evaluate(x=test_x,y=test_y,batch_size=128)
    # 保存整个网络
    model.save("cifar10model.h5")
    """
    # https://blog.csdn.net/jiandanjinxin/article/details/77152530
    # 使用
    # keras.models.load_model("cifar10model.h5")
    

    只保存architecture

    json_string = model.to_json()

    open(‘my_model_architecture.json’,‘w’).write(json_string)

    使用

    from keras.models import model_from_json

    #model = model_from_json(open(‘my_model_architecture.json’).read())

    只保存weights

    model.save_weights(‘my_model_weights.h5’)

    #需要在代码中初始化一个完全相同的模型

    model.load_weights(‘my_model_weights.h5’)

    #需要加载权重到不同的网络结构(有些层一样)中,例如fine-tune或transfer-learning,可以通过层名字来加载模型

    model.load_weights(‘my_model_weights.h5’, by_name=True)

    “”"

    pytorch 流程

    model = myModel()
    # Loss and optimizer
    criterion = nn.CrossEntropyLoss()
    

    for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
    images = images.to(device)
    labels = labels.to(device)

    # Forward pass
    outputs = model(images)
    loss = criterion(outputs, labels)
    
    # Backward and optimize
    	# 将上次迭代计算的梯度值清0
    optimizer.zero_grad()
    # 反向传播,计算梯度值
    loss.backward()
    # 更新权值参数
    optimizer.step()
    

    model.eval(),让model变成测试模式,对dropout和batch normalization的操作在训练和测试的时候是不一样的

    eval()时,pytorch会自动把BN和DropOut固定住,不会取平均,而是用训练好的值。

    不然的话,一旦test的batch_size过小,很容易就会被BN层导致生成图片颜色失真极大。

    model.eval()
    with torch.no_grad():
    correct = 0
    total = 0
    for images, labels in test_loader:
    images = images.to(device)
    labels = labels.to(device)
    outputs = model(images)
    _, predicted = torch.max(outputs.data, 1)
    total += labels.size(0)
    correct += (predicted == labels).sum().item()

    print(‘Accuracy of the model on the test images: {} %’.format(100 * correct / total))

    Save the model checkpoint

    这是只保存了weights

    torch.save(model.state_dict(), ‘resnet.ckpt’)
    “”"

    使用

    myModel.load_state_dict(torch.load(‘params.ckpt’))

    若想保存整个网络(architecture + weights)

    torch.save(resnet, ‘model.ckpt’)

    使用

    #model = torch.load(‘model.ckpt’)
    “”"

    对比流程

    #https://blog.csdn.net/dss_dssssd/article/details/83892824
    """
    1: 准备数据(注意数据格式不同)
    2: 定义网络结构model
    3: 定义损失函数
    4: 定义优化算法 optimizer
    5: 训练-keras
    	5.1:编译模型(传入loss function和optimizer等)
    	5.2:训练模型(fit or fit_generator,传入数据)
    5: 训练-pytorch
    迭代训练:
    	5.1:准备好tensor形式的输入数据和标签(可选)
    	5.2:前向传播计算网络输出output和计算损失函数loss
    	5.3:反向传播更新参数
    		以下三句话一句也不能少:
    		5.3.1:将上次迭代计算的梯度值清0
    			optimizer.zero_grad()
    		5.3.2:反向传播,计算梯度值
    			loss.backward()
    		5.3.3:更新权值参数
    			optimizer.step()
    6: 在测试集上测试-keras
    	model.evaluate
    6: 在测试集上测试-pytorch
      遍历测试集,自定义metric
    7: 保存网络(可选) 具体实现参考上面代码
    """
    

    构建网络

    对比网络

    1、对于keras,不需要input_channels,函数内部会自动获得,而pytorch则需要显示声明input_channels

    2、对于pytorch Conv2d需要指定padding,而keras的则是same和valid两种选项(valid即padding=0)

    3、keras的Flatten操作可以视作pytorch中的view

    4、keras的dimension一般顺序是(H, W, C) (tensorflow 为backend的话),而pytorch的顺序则是( C, H, W)

    5、具体的变换可以参照下方,但由于没有学过pytorch,keras也刚入门,不能保证正确,日后学的更深入了之后再来看看。

    pytorch 构建Residual-network

    import torch
    import torch.nn as nn
    import torchvision
    import torchvision.transforms as transforms
    

    Device configuration

    device = torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’)

    Hyper-parameters

    num_epochs = 80
    learning_rate = 0.001

    Image preprocessing modules

    transform = transforms.Compose([
    transforms.Pad(4),
    transforms.RandomHorizontalFlip(),
    transforms.RandomCrop(32),
    transforms.ToTensor()])

    CIFAR-10 dataset

    train_dataset.data.shape

    #Out[31]: (50000, 32, 32, 3)

    train_dataset.targets list

    len(list)=5000

    train_dataset = torchvision.datasets.CIFAR10(root=’./data/’,
    train=True,
    transform=transform,
    download=True)

    test_dataset = torchvision.datasets.CIFAR10(root=’…/…/data/’,
    train=False,
    transform=transforms.ToTensor())

    Data loader

    train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
    batch_size=100,
    shuffle=True)

    test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
    batch_size=100,
    shuffle=False)

    3x3 convolution

    def conv3x3(in_channels, out_channels, stride=1):
    return nn.Conv2d(in_channels, out_channels, kernel_size=3,
    stride=stride, padding=1, bias=False)

    Residual block

    class ResidualBlock(nn.Module):
    def init(self, in_channels, out_channels, stride=1, downsample=None):
    super(ResidualBlock, self).init()
    self.conv1 = conv3x3(in_channels, out_channels, stride)
    self.bn1 = nn.BatchNorm2d(out_channels)
    self.relu = nn.ReLU(inplace=True)
    self.conv2 = conv3x3(out_channels, out_channels)
    self.bn2 = nn.BatchNorm2d(out_channels)
    self.downsample = downsample

    def forward(self, x):
    residual = x
    out = self.conv1(x)
    out = self.bn1(out)
    out = self.relu(out)
    out = self.conv2(out)
    out = self.bn2(out)
    if self.downsample:
    residual = self.downsample(x)
    out += residual
    out = self.relu(out)
    return out

    ResNet

    class ResNet(nn.Module):
    def init(self, block, layers, num_classes=10):
    super(ResNet, self).init()
    self.in_channels = 16
    self.conv = conv3x3(3, 16)
    self.bn = nn.BatchNorm2d(16)
    self.relu = nn.ReLU(inplace=True)
    self.layer1 = self.make_layer(block, 16, layers[0])
    self.layer2 = self.make_layer(block, 32, layers[1], 2)
    self.layer3 = self.make_layer(block, 64, layers[2], 2)
    self.avg_pool = nn.AvgPool2d(8)
    self.fc = nn.Linear(64, num_classes)

    def make_layer(self, block, out_channels, blocks, stride=1):
    downsample = None
    if (stride != 1) or (self.in_channels != out_channels):
    downsample = nn.Sequential(
    conv3x3(self.in_channels, out_channels, stride=stride),
    nn.BatchNorm2d(out_channels))
    layers = []
    layers.append(block(self.in_channels, out_channels, stride, downsample))
    self.in_channels = out_channels
    for i in range(1, blocks):
    layers.append(block(out_channels, out_channels))
    # [*[1,2,3]]
    # Out[96]: [1, 2, 3]
    return nn.Sequential(*layers)

    def forward(self, x):
    out = self.conv(x) # out.shape:torch.Size([100, 16, 32, 32])
    out = self.bn(out)
    out = self.relu(out)
    out = self.layer1(out)
    out = self.layer2(out)
    out = self.layer3(out)
    out = self.avg_pool(out)
    out = out.view(out.size(0), -1)
    out = self.fc(out)
    return out

    model = ResNet(ResidualBlock, [2, 2, 2]).to(device)

    pip install torchsummary or

    git clone https://github.com/sksq96/pytorch-summary

    from torchsummary import summary

    input_size=(C,H,W)

    summary(model, input_size=(3, 32, 32))

    images,labels = iter(train_loader).next()
    outputs = model(images)

    Loss and optimizer

    criterion = nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

    For updating learning rate

    def update_lr(optimizer, lr):
    for param_group in optimizer.param_groups:
    param_group[‘lr’] = lr

    Train the model

    total_step = len(train_loader)
    curr_lr = learning_rate
    for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
    images = images.to(device)
    labels = labels.to(device)

    # Forward pass
    outputs = model(images)
    loss = criterion(outputs, labels)
    
    # Backward and optimize
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    if (i+1) % 100 == 0:
      print ("Epoch [{}/{}], Step [{}/{}] Loss: {:.4f}"
          .format(epoch+1, num_epochs, i+1, total_step, loss.item()))
    

    Decay learning rate

    if (epoch+1) % 20 == 0:
    curr_lr /= 3
    update_lr(optimizer, curr_lr)

    Test the model

    model.eval()
    with torch.no_grad():
    correct = 0
    total = 0
    for images, labels in test_loader:
    images = images.to(device)
    labels = labels.to(device)
    outputs = model(images)
    _, predicted = torch.max(outputs.data, 1)
    total += labels.size(0)
    correct += (predicted == labels).sum().item()

    print(‘Accuracy of the model on the test images: {} %’.format(100 * correct / total))

    Save the model checkpoint

    torch.save(model.state_dict(), ‘resnet.ckpt’)

    keras 对应的网络构建部分

    """
    #pytorch
    def conv3x3(in_channels, out_channels, stride=1):
      return nn.Conv2d(in_channels, out_channels, kernel_size=3, 
               stride=stride, padding=1, bias=False)
    """
    

    def conv3x3(x,out_channels, stride=1):
    #out = spatial_2d_padding(x,padding=((1, 1), (1, 1)), data_format=“channels_last”)
    return Conv2D(filters=out_channels, kernel_size=[3,3], strides=(stride,stride),padding=“same”)(x)

    “”"

    pytorch

    Residual block

    class ResidualBlock(nn.Module):
    def init(self, in_channels, out_channels, stride=1, downsample=None):
    super(ResidualBlock, self).init()
    self.conv1 = conv3x3(in_channels, out_channels, stride)
    self.bn1 = nn.BatchNorm2d(out_channels)
    self.relu = nn.ReLU(inplace=True)
    self.conv2 = conv3x3(out_channels, out_channels)
    self.bn2 = nn.BatchNorm2d(out_channels)
    self.downsample = downsample

    def forward(self, x):
    residual = x
    out = self.conv1(x)
    out = self.bn1(out)
    out = self.relu(out)
    out = self.conv2(out)
    out = self.bn2(out)
    if self.downsample:
    residual = self.downsample(x)
    out += residual
    out = self.relu(out)
    return out
    “”"
    def ResidualBlock(x, out_channels, stride=1, downsample=False):
    residual = x
    out = conv3x3(x, out_channels,stride)
    out = BatchNormalization()(out)
    out = Activation(“relu”)(out)
    out = conv3x3(out, out_channels)
    out = BatchNormalization()(out)
    if downsample:
    residual = conv3x3(residual, out_channels, stride=stride)
    residual = BatchNormalization()(residual)
    out = keras.layers.add([residual,out])
    out = Activation(“relu”)(out)
    return out
    “”"
    #pytorch
    def make_layer(self, block, out_channels, blocks, stride=1):
    downsample = None
    if (stride != 1) or (self.in_channels != out_channels):
    downsample = nn.Sequential(
    conv3x3(self.in_channels, out_channels, stride=stride),
    nn.BatchNorm2d(out_channels))
    layers = []
    layers.append(block(self.in_channels, out_channels, stride, downsample))
    self.in_channels = out_channels
    for i in range(1, blocks):
    layers.append(block(out_channels, out_channels))
    # [*[1,2,3]]
    # Out[96]: [1, 2, 3]
    return nn.Sequential(*layers)
    “”"
    def make_layer(x, out_channels, blocks, stride=1):
    # tf backend: x.output_shape[-1]==out_channels
    #print("x.shape[-1] ",x.shape[-1])
    downsample = False
    if (stride != 1) or (out_channels != x.shape[-1]):
    downsample = True
    out = ResidualBlock(x, out_channels, stride, downsample)
    for i in range(1, blocks):
    out = ResidualBlock(out, out_channels)
    return out

    def KerasResidual(input_shape):
    images = Input(input_shape)
    out = conv3x3(images,16) # out.shape=(None, 32, 32, 16)
    out = BatchNormalization()(out)
    out = Activation(“relu”)(out)
    layer1_out = make_layer(out, 16, layers[0])
    layer2_out = make_layer(layer1_out, 32, layers[1], 2)
    layer3_out = make_layer(layer2_out, 64, layers[2], 2)
    out = AveragePooling2D(pool_size=(8,8))(layer3_out)
    out = Flatten()(out)

    pytorch 的nn.CrossEntropyLoss()会首先执行softmax计算

    当换成keras时,没有tf类似的softmax_cross_entropy

    自带的categorical_crossentropy不会执行激活操作,因此得在Dense层加上activation

    out = Dense(units=10, activation=“softmax”)(out)
    model = Model(inputs=images,outputs=out)
    return model

    input_shape=(32, 32, 3)
    layers=[2, 2, 2]
    mymodel = KerasResidual(input_shape)
    mymodel.summary()

    pytorch model summary

    ----------------------------------------------------------------
        Layer (type)        Output Shape     Param #
    ================================================================
          Conv2d-1      [-1, 16, 32, 32]       432
        BatchNorm2d-2      [-1, 16, 32, 32]       32
           ReLU-3      [-1, 16, 32, 32]        0
          Conv2d-4      [-1, 16, 32, 32]      2,304
        BatchNorm2d-5      [-1, 16, 32, 32]       32
           ReLU-6      [-1, 16, 32, 32]        0
          Conv2d-7      [-1, 16, 32, 32]      2,304
        BatchNorm2d-8      [-1, 16, 32, 32]       32
           ReLU-9      [-1, 16, 32, 32]        0
      ResidualBlock-10      [-1, 16, 32, 32]        0
          Conv2d-11      [-1, 16, 32, 32]      2,304
       BatchNorm2d-12      [-1, 16, 32, 32]       32
           ReLU-13      [-1, 16, 32, 32]        0
          Conv2d-14      [-1, 16, 32, 32]      2,304
       BatchNorm2d-15      [-1, 16, 32, 32]       32
           ReLU-16      [-1, 16, 32, 32]        0
      ResidualBlock-17      [-1, 16, 32, 32]        0
          Conv2d-18      [-1, 32, 16, 16]      4,608
       BatchNorm2d-19      [-1, 32, 16, 16]       64
           ReLU-20      [-1, 32, 16, 16]        0
          Conv2d-21      [-1, 32, 16, 16]      9,216
       BatchNorm2d-22      [-1, 32, 16, 16]       64
          Conv2d-23      [-1, 32, 16, 16]      4,608
       BatchNorm2d-24      [-1, 32, 16, 16]       64
           ReLU-25      [-1, 32, 16, 16]        0
      ResidualBlock-26      [-1, 32, 16, 16]        0
          Conv2d-27      [-1, 32, 16, 16]      9,216
       BatchNorm2d-28      [-1, 32, 16, 16]       64
           ReLU-29      [-1, 32, 16, 16]        0
          Conv2d-30      [-1, 32, 16, 16]      9,216
       BatchNorm2d-31      [-1, 32, 16, 16]       64
           ReLU-32      [-1, 32, 16, 16]        0
      ResidualBlock-33      [-1, 32, 16, 16]        0
          Conv2d-34       [-1, 64, 8, 8]     18,432
       BatchNorm2d-35       [-1, 64, 8, 8]       128
           ReLU-36       [-1, 64, 8, 8]        0
          Conv2d-37       [-1, 64, 8, 8]     36,864
       BatchNorm2d-38       [-1, 64, 8, 8]       128
          Conv2d-39       [-1, 64, 8, 8]     18,432
       BatchNorm2d-40       [-1, 64, 8, 8]       128
           ReLU-41       [-1, 64, 8, 8]        0
      ResidualBlock-42       [-1, 64, 8, 8]        0
          Conv2d-43       [-1, 64, 8, 8]     36,864
       BatchNorm2d-44       [-1, 64, 8, 8]       128
           ReLU-45       [-1, 64, 8, 8]        0
          Conv2d-46       [-1, 64, 8, 8]     36,864
       BatchNorm2d-47       [-1, 64, 8, 8]       128
           ReLU-48       [-1, 64, 8, 8]        0
      ResidualBlock-49       [-1, 64, 8, 8]        0
        AvgPool2d-50       [-1, 64, 1, 1]        0
          Linear-51          [-1, 10]       650
    ================================================================
    Total params: 195,738
    Trainable params: 195,738
    Non-trainable params: 0
    ----------------------------------------------------------------
    Input size (MB): 0.01
    Forward/backward pass size (MB): 3.63
    Params size (MB): 0.75
    Estimated Total Size (MB): 4.38
    ----------------------------------------------------------------
    

    keras model summary

    __________________________________________________________________________________________________
    Layer (type)          Output Shape     Param #   Connected to           
    ==================================================================================================
    input_26 (InputLayer)      (None, 32, 32, 3)  0                      
    __________________________________________________________________________________________________
    conv2d_103 (Conv2D)       (None, 32, 32, 16)  448     input_26[0][0]          
    __________________________________________________________________________________________________
    batch_normalization_99 (BatchNo (None, 32, 32, 16)  64     conv2d_103[0][0]         
    __________________________________________________________________________________________________
    activation_87 (Activation)   (None, 32, 32, 16)  0      batch_normalization_99[0][0]   
    __________________________________________________________________________________________________
    conv2d_104 (Conv2D)       (None, 32, 32, 16)  2320    activation_87[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_100 (BatchN (None, 32, 32, 16)  64     conv2d_104[0][0]         
    __________________________________________________________________________________________________
    activation_88 (Activation)   (None, 32, 32, 16)  0      batch_normalization_100[0][0]  
    __________________________________________________________________________________________________
    conv2d_105 (Conv2D)       (None, 32, 32, 16)  2320    activation_88[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_101 (BatchN (None, 32, 32, 16)  64     conv2d_105[0][0]         
    __________________________________________________________________________________________________
    add_34 (Add)          (None, 32, 32, 16)  0      activation_87[0][0]       
                                     batch_normalization_101[0][0]  
    __________________________________________________________________________________________________
    activation_89 (Activation)   (None, 32, 32, 16)  0      add_34[0][0]           
    __________________________________________________________________________________________________
    conv2d_106 (Conv2D)       (None, 32, 32, 16)  2320    activation_89[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_102 (BatchN (None, 32, 32, 16)  64     conv2d_106[0][0]         
    __________________________________________________________________________________________________
    activation_90 (Activation)   (None, 32, 32, 16)  0      batch_normalization_102[0][0]  
    __________________________________________________________________________________________________
    conv2d_107 (Conv2D)       (None, 32, 32, 16)  2320    activation_90[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_103 (BatchN (None, 32, 32, 16)  64     conv2d_107[0][0]         
    __________________________________________________________________________________________________
    add_35 (Add)          (None, 32, 32, 16)  0      activation_89[0][0]       
                                     batch_normalization_103[0][0]  
    __________________________________________________________________________________________________
    activation_91 (Activation)   (None, 32, 32, 16)  0      add_35[0][0]           
    __________________________________________________________________________________________________
    conv2d_108 (Conv2D)       (None, 16, 16, 32)  4640    activation_91[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_104 (BatchN (None, 16, 16, 32)  128     conv2d_108[0][0]         
    __________________________________________________________________________________________________
    activation_92 (Activation)   (None, 16, 16, 32)  0      batch_normalization_104[0][0]  
    __________________________________________________________________________________________________
    conv2d_110 (Conv2D)       (None, 16, 16, 32)  4640    activation_91[0][0]       
    __________________________________________________________________________________________________
    conv2d_109 (Conv2D)       (None, 16, 16, 32)  9248    activation_92[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_106 (BatchN (None, 16, 16, 32)  128     conv2d_110[0][0]         
    __________________________________________________________________________________________________
    batch_normalization_105 (BatchN (None, 16, 16, 32)  128     conv2d_109[0][0]         
    __________________________________________________________________________________________________
    add_36 (Add)          (None, 16, 16, 32)  0      batch_normalization_106[0][0]  
                                     batch_normalization_105[0][0]  
    __________________________________________________________________________________________________
    activation_93 (Activation)   (None, 16, 16, 32)  0      add_36[0][0]           
    __________________________________________________________________________________________________
    conv2d_111 (Conv2D)       (None, 16, 16, 32)  9248    activation_93[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_107 (BatchN (None, 16, 16, 32)  128     conv2d_111[0][0]         
    __________________________________________________________________________________________________
    activation_94 (Activation)   (None, 16, 16, 32)  0      batch_normalization_107[0][0]  
    __________________________________________________________________________________________________
    conv2d_112 (Conv2D)       (None, 16, 16, 32)  9248    activation_94[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_108 (BatchN (None, 16, 16, 32)  128     conv2d_112[0][0]         
    __________________________________________________________________________________________________
    add_37 (Add)          (None, 16, 16, 32)  0      activation_93[0][0]       
                                     batch_normalization_108[0][0]  
    __________________________________________________________________________________________________
    activation_95 (Activation)   (None, 16, 16, 32)  0      add_37[0][0]           
    __________________________________________________________________________________________________
    conv2d_113 (Conv2D)       (None, 8, 8, 64)   18496    activation_95[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_109 (BatchN (None, 8, 8, 64)   256     conv2d_113[0][0]         
    __________________________________________________________________________________________________
    activation_96 (Activation)   (None, 8, 8, 64)   0      batch_normalization_109[0][0]  
    __________________________________________________________________________________________________
    conv2d_115 (Conv2D)       (None, 8, 8, 64)   18496    activation_95[0][0]       
    __________________________________________________________________________________________________
    conv2d_114 (Conv2D)       (None, 8, 8, 64)   36928    activation_96[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_111 (BatchN (None, 8, 8, 64)   256     conv2d_115[0][0]         
    __________________________________________________________________________________________________
    batch_normalization_110 (BatchN (None, 8, 8, 64)   256     conv2d_114[0][0]         
    __________________________________________________________________________________________________
    add_38 (Add)          (None, 8, 8, 64)   0      batch_normalization_111[0][0]  
                                     batch_normalization_110[0][0]  
    __________________________________________________________________________________________________
    activation_97 (Activation)   (None, 8, 8, 64)   0      add_38[0][0]           
    __________________________________________________________________________________________________
    conv2d_116 (Conv2D)       (None, 8, 8, 64)   36928    activation_97[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_112 (BatchN (None, 8, 8, 64)   256     conv2d_116[0][0]         
    __________________________________________________________________________________________________
    activation_98 (Activation)   (None, 8, 8, 64)   0      batch_normalization_112[0][0]  
    __________________________________________________________________________________________________
    conv2d_117 (Conv2D)       (None, 8, 8, 64)   36928    activation_98[0][0]       
    __________________________________________________________________________________________________
    batch_normalization_113 (BatchN (None, 8, 8, 64)   256     conv2d_117[0][0]         
    __________________________________________________________________________________________________
    add_39 (Add)          (None, 8, 8, 64)   0      activation_97[0][0]       
                                     batch_normalization_113[0][0]  
    __________________________________________________________________________________________________
    activation_99 (Activation)   (None, 8, 8, 64)   0      add_39[0][0]           
    __________________________________________________________________________________________________
    average_pooling2d_2 (AveragePoo (None, 1, 1, 64)   0      activation_99[0][0]       
    __________________________________________________________________________________________________
    flatten_2 (Flatten)       (None, 64)      0      average_pooling2d_2[0][0]    
    __________________________________________________________________________________________________
    dense_2 (Dense)         (None, 10)      650     flatten_2[0][0]         
    ==================================================================================================
    Total params: 197,418
    Trainable params: 196,298
    Non-trainable params: 1,120
    __________________________________________________________________________________________________
    

    以上这篇keras的三种模型实现与区别说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持菜鸟教程www.piaodoo.com。

    展开全文
  • 本文只是打算介绍近期总结的三种边界触发模式的实现方式,后面会实现每一种然后做一个性能比较. 1)模仿windows完成端口的模式. 这是最早的时候想到的一种方法,并且已经用C++实现过.大概结构这样的, 定义了一个...

    本文并不打算介绍边界触发模式,需要了解的朋友自己到网上搜索.

     

    本文只是打算介绍近期总结的三种边界触发模式的实现方式,后面会实现每一种然后做一个性能比较.

    1)模仿windows完成端口的模式.

    这是最早的时候想到的一种方法,并且已经用C++实现过.大概结构这样的,

    定义了一个IO请求结构,类似于IOCP的OVERLAP结构:

    struct OVERLAP
    {
    void *buf;
    int bytetransfer;
    int errcode;
    };

    然后是一个对应用不透明的socket结构:

    struct socket_t
    {
    volatile int readable;
    volatile int writeable;
    list * pending_read;
    list * pending_write;
    };

    向上层提供了两个发送/接受接口

    int WSASend(socket_t*,OVERLAP*);
    int WSARecv(socket_t*,OVERLAP*);

    如果网络操作无法立即完成(readable/writeable == 0 或 read/write的错误码是EWOULDBLOCK)

    则将请求保存在pending_read/pending_write中.

     

    在epoll线程中,如果发现一个套接口被激活,则将其readable/writeable设置为1,并查看pending

    list 中是否有未完成的请求,如果有,则弹一个出来执行,然后往完成队列中添加一个完成事件.

    下面是WSARecv的伪代码:

    int WSARecv(s,overlap)
    {
    if !s.readable then
    s.pending_read.push_back(overlap)
    return IO_PENDING
    end

    int bytetransfer = read(overlap.buf,overlap.bytetransfer)
    if bytetransfer < 0 then
    if errno == EWOULDBLOCK then
           s.readable = 0  
    s.pending_read.push_back(overlap)
    return IO_PENDING
    end
    end

    return bytetransfer

    }

    epoll中套接口被激活的伪代码:

    void OnReadActive(s)
    {
    s.readable = 1
    ioreq = s.pending_read.pop_front()
    if ioreq ~= nil then
    //弹出一个请求,执行,然后投递一个完成通告
    int bytetransfer = read(ioreq.buf,ioreq.bytetransfer)
    ioreq.bytetransfer = bytetransfer
    IOCompleteEventQueue.push_back(ioreq)
    end
    }

     

    完成例程的伪码如下:

    void complete_routine()
    {
    complete_status = GetCompleteStatus()
    s = GetSocket(complete_status)
    do
    ret = WSARecv(s,complete_status)
    while( ret!= IO_PENDING)
    }

     

    注:这个模式在最开始的时候实际的IO操作是交由另外的IO工作线程完成的,IO完成后投递完成通告

    这样,即使IO立即可以完成也会投递完成通告,在IO繁忙时对完成队列的操作消耗也是不小的。改进

    之后,只有当套接字从未激活态变为激活态,且有IO请求时才会投递一次完成通告(IOCP已经增加了类似

    的选项FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)

     

    2)跟模式1类似,区别如下:

    void OnReadActive(s)
    {
    s.readable = 1
    ioreq = s.pending_read.pop_front()
    if ioreq ~= nil then
    IOCompleteEventQueue.push_back(ioreq)
    end
    }

    也就是epoll线程完全不执行实际的IO请求,所有的请求都由用户提供的完成线程执行.此时完成队列

    实际上并不存放完成事件,存放的只是pending的IO操作.

    此时Read操作也分成两个

    int WSARead(s,overlap)
    {
    s.pending_read.push_back(overlap)
    req = pending_read.pop_front()
    IOCompleteEventQueue.push_back(req)//仅仅投递一个请求,不尝试完成操作
    }

    //此函数在完成例程中调用
    int raw_read(s,overlap)
    {
    if !s.readable then
    s.pending_read.push_back(overlap)
    return IO_PENDING
    end

    int bytetransfer = read(overlap.buf,overlap.bytetransfer)
    if bytetransfer < 0 then
    if errno == EWOULDBLOCK then
    s.readable = 0
    s.pending_read.push_back(overlap)
    return IO_PENDING
    end
    end

    return bytetransfer
    }

    3)IO操作全部都在epoll线程中执行, 要充分利用多核CPU多启动几个epoll线程即可.

     

    每个epoll对上层提供一个队列IO_queue,用以保存IO请求.上层请求IO时仅仅是往这

    个队列中放入一个元素即可.

    epoll线程主循环伪代码如下:

    void main_loop()
    {
    while(true)
    {
    local_queue = IO_queue //将IO_queue中的所有请求同步到local_queue中
    while(req = local_queue.pop_front)
    {
    //保证请求按提交的顺序被执行
    req.s.pending_read.push_back(req)
    req = s.pending_read.pop_front()
    //执行请求,如果请求无法完成,重新插入到pending队列的头部
    }
    //epoll_wait............
    for all active s do
    OnReadActive(s)
    end
    }
    }

    void OnReadActive(s)
    {
    s.readable = 1
    while(ioreq = s.pending_read.pop_front())
    {
    read(ioreq.buf,ioreq.bytetransfer)
    //操作完成,回调用一个用户提供的函数
    }
    }



    转载于:https://www.cnblogs.com/sniperHW/archive/2012/04/07/2436385.html

    展开全文
  • 而节理作为一重要的结构面,可以借助统计学原理,对边坡节理面产状进行调查并分析,建立出等效节理面网络模型,为之后岩体稳定性分析奠定良好基础。通过VC++语言编程建立了等效节理岩体网络模型的专用...
  • 7.3 VC++对多线程网络编程的支持 192 7.3.1 MFC支持的两线程 192 7.3.2 创建MFC的工作线程 193 7.3.3 创建并启动用户界面线程 195 7.3.4 终止线程 198 7.4 多线程FTP客户端实例 200 7.4.1 编写线程...
  • linux网络编程

    2019-07-11 00:07:03
    23进程间通信介绍(一) 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 ...
  • 关于网络编程基础知识学习教学文件,章节有网络编程概述、网络相关术语、网络分层体系结构、即时通信的三种模式、C# Socket通信过程、WebSocket 编程。内容知识点设计网络编程基础、OSI/RM、TCP/IP模型、Socket网络...
  • 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) ...
  • 我将网络模型放在了《网络编程系列》第一篇,是因为它是整个网络知识体系根基。 作为一个网络常识,虽然简单,但面试官可能会将之作为开篇方式提问,然后他会借此展开深入追问其他网络知识,所以还是有必要...

    我将网络模型放在了《网络编程系列》的第一篇,是因为它是整个网络知识体系的根基。

    作为一个网络常识,虽然简单,但面试官可能会将之作为开篇方式提问,然后他会借此展开深入追问其他的网络知识,所以还是有必要复习下。

    1、综述

    计算机网络是一个非常庞大且复杂的系统,所以在设计之初就严格遵守着「分层」的设计理念。

    主流网络分层体系结构有两种:

    OSI(Open Systems Interconnection Reference Model,开放系统互联参考模型),就是常说的七层网络模型。

    TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/因特网协议)四层网络模型,也有人愿意归为 “五层网络模型”,以其中最重要的 TCP 协议和 IP 协议命名。

    在这里插入图片描述
    值得一提的是,由国际化标准组织制定的 OSI 模型,本来是最应该在全球范围内推广的网络模型,不过因为 OSI 的设计过于理想不合实际,再加上当时应用 TCP/IP 模型的因特网(Internet)已经覆盖了全球大部分地区。种种原因,导致 OSI 并没有取得市场化的成功,仅仅是获得了理论上的研究成果。而 TCP/IP 模型则被作为了事实上的国际标准

    还有一种分层体系是五层。

    在这里插入图片描述

    2、TCP/IP四层网络模型

    目标是了解各层的作用与相应的协议。

    2.1、网络接口层

    网络访问层的功能包括IP地址与物理地址的映射,以及将上一层的IP报文封装成帧

    基于不同类型的网络接口,网络访问层定义了与物理介质的连接。网络访问层包括了数据链路层的地址,因为可以看到源MAC和目标MAC。它是TCP/IP协议的最底层,负责接收从网络层传来的IP数据报,并且将IP数据报拆包之后通过底层物理网络发出去,或者从底层的物理网络上接收物理帧,解封装出IP数据报,交给网际层处理。

    数据链路层两个常用的协议是ARP协议(Address Resolve Protocol,地址解析协议)和RARP协议(ReverseAddress Resolve Protocol,逆地址解析协议)。它们实现了IP地址和机器物理地址(通常是MAC地址,以太网、令牌环和802.11无线网络都使用MAC地址)之间的相互转换。

    网络层使用IP地址寻址一台机器,而数据链路层使用物理地址寻址一台机器,因此网络层必须先将目标机器的IP地址转化成其物理地址,才能使用数据链路层提供的服务,这就是ARP协议的用途。

    RARP协议仅用于网络上的某些无盘工作站。因为缺乏存储设备,无盘工作站无法记住自己的IP地址,但它们可以利用网卡上的物理地址来向网络管理者(服务器或网络管理软件)查询自身的IP地址。运行RARP服务的网络管理者通常存有该网络上所有机器的物理地址到IP地址的映射。

    2.2、网络层(网际层)

    网络层最核心的协议是IP协议(Internet Protocol,因特网协议)。IP协议根据数据包的目的IP地址来决定如何投递它。如果数据包不能直接发送给目标主机,那么IP协议就为它寻找一个合适的下一跳(next hop)路由器,并将数据包交付给该路由器来转发。多次重复这一过程,数据包最终到达目标主机,或者由于发送失败而被丢弃。可见,IP协议使用逐跳(hop by hop)的方式确定通信路径。

    网络层另外一个重要的协议是ICMP协议(Internet Control Message Protocol,因特网控制报文协议)。它是IP协议的重要补充,主要用于检测网络连接

    2.3、传输层

    传输层为两台主机上的应用程序提供端到端(end to end)的通信。与网络层使用的逐跳通信方式不同,传输层只关心通信的起始端和目的端,而不在乎数据包的中转过程。

    传输层协议:TCP协议、UDP协议。

    2.4、应用层

    应用层负责处理应用程序的逻辑
    数据链路层、网络层和传输层负责处理网络通信细节,这部分必须既稳定又高效,因此它们都在内核空间中实现。而应用层则在用户空间实现,因为它负责处理众多逻辑,比如文件传输、名称查询和网络管理等。如果应用层也在内核中实现,则会使内核变得非常庞大。当然,也有少数服务器程序是在内核中实现的,这样代码就无须在用户空间和内核空间来回切换(主要是数据的复制),极大地提高了工作效率。不过这种代码实现起来较复杂,不够灵活,且不便于移植。

    ping是应用程序,而不是协议,前面说过它利用ICMP报文检测网络连接,是调试网络环境的必备工具。

    telnet协议是一种远程登录协议,它使我们能在本地完成远程任务。

    OSPF(Open Shortest Path First,开放最短路径优先)协议是一种动态路由更新协议,用于路由器之间的通信,以告知对方各自的路由信息。

    DNS(Domain Name Service,域名服务)协议提供机器域名到IP地址的转换。

    应用层协议(或程序)可能跳过传输层直接使用网络层提供的服务,比如ping程序和OSPF协议。应用层协议(或程序)通常既可以使用TCP服务,又可以使用UDP服务,比如DNS协议。我们可以通过/etc/services文件查看所有知名的应用层协议,以及它们都能使用哪些传输层服务。

    3、总结

    各层的主要协议如下:

    数据链路层(驱动程序)封装了物理网络的电气细节;网络层封装了网络连接的细节;传输层则为应用程序封装了一条端到端的逻辑通信链路,它负责数据的收发、链路的超时重连等。

    为何要将网络协议划分成若干层,或者说分层的好处有哪些?
    1.各层次之间是独立的。某一层并不需要知道它的下一层是如何实现的,而仅仅需要知道该层通过层间的接口所提供的服务。这样,整个问题的复杂程度就下降了。也就是说上一层的工作如何进行并不影响下一层的工作,这样我们在进行每一层的工作设计时只要保证接口不变可以随意调整层内的工作方式。

    2.稳定。当任何一层发生变化时,只要层间接口关系保持不变,则在这层以上或以下层均不受影响。当某一层出现技术革新或者某一层在工作中出现问题时不会连累到其它层的工作,排除问题时也只需要考虑这一层单独的问题即可。

    3.结构上可分割开。各层都可以采用最合适的技术来实现。技术的发展往往不对称的,层次化的划分有效避免了木桶效应,不会因为某一方面技术的不完善而影响整体的工作效率。

    4.易于实现和维护。这种结构使得实现和调试一个庞大又复杂的系统变得易于处理,因为整个的系统已经被分解为若干个相对独立的子系统。进行调试和维护时,可以对每一层进行单独的调试,避免了出现找不到、解决错问题的情况。

    5.能促进标准化工作。因为每一层的功能及其所提供的服务都已有了精确的说明。标准化的好处就是可以随意替换其中的某一层,对于使用和科研来说十分方便。

    问题汇总

    1、分层的好处
    独立、稳定、易于实现和维护、能促进标准化工作
    2、说出tcp/ip四层网络模型的层次以及各自职责
    3、每一层的寻址依据
    网络接口层:MAC地址
    网络层:IP地址
    传输层:端口
    应用层:端口(例如ftp 23,http 80)

    展开全文
  • 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) ...
  • 理解OSI七层模型理论,理解TCP/IP模型的四层结构:应用层,传输层,网络层,网络接口层。 TCP/IP协议包含非常多协议,TCP和IP只不过是其中最有代表性。 C/S结构:代表IM,属于TCP SOCKET编程; B/S结构:...

    TCP/IP知识略过,大致总结一下几点

    1. 理解OSI七层模型理论,理解TCP/IP模型的四层结构:应用层,传输层,网络层,网络接口层。
    2. TCP/IP协议包含非常多的协议,TCP和IP只不过是其中最有代表性的两种。
    3. C/S结构:代表IM,属于TCP SOCKET编程; B/S结构:代表JD商城,属于HTTP编程,HTTP也是TCP/IP协议的一部分。
    4. 关于网络部分,必须深刻理解TCP/IP,才能做好后续开发,本处不再赘述。
    5. 端口少开,多开一个多一份风险,服务器能少开端口就少开;系统必须纯净版;单端口对应单程序,不能复用;

    TCP SOCKET编程的Client端和Server端

    1. 一般是多Client对应少数Server。
    2. 服务器端的处理流程:
      监听端口(Listening);
      接收客户端的TCP请求,建立客户端与服务器端链接;
      创建goroutine,处理该链接请求(Client通过发送请求包)。
    3. 客户端的处理流程:
      建立与服务端的链接(通过随机定义的端口链接服务器监听端口);
      发送请求数据,接收服务器端返回的结果数据;
      关闭链接(TCP占资源开销,类似打开文件要defer关闭防止内存泄漏);

    实战练习,写一个Server和Client的C/S模型发送接收信息,终端输入,终端输出

    server端及注释分析:

    package main
    
    import (
    	"fmt"
    	"net"
    )
    
    func recv(conn net.Conn) {
    	//循环接收客户端发送来的请求
    	defer conn.Close()    //如果不关闭服务器因为连接没有释放,后续客户端无法登陆了
    	for {
    		//创建一个新的切片
    		buf := make([]byte,1024)
    		//fmt.Printf("服务器在等待客户端%v发送信息\n",conn.RemoteAddr().String())
    		n, err := conn.Read(buf)  //如果客户端conn不发信息,没有write操作,会一直阻塞,优化做一个timeout
    		if err != nil {
    			return
    		}
    		//显示信息到服务器终端,buf[:n]是真正读到的信息,否则切片后一大串东西都会出来,很乱套
    		fmt.Print(string(buf[:n]))
    	}
    }
    
    func main() {
    	/*
    	需求分析:
    	1. 服务端: 监听端口6666,要为多个客户端提供服务;
    	   不能阻塞,所以每个客户端请求都用一个goroutine提供服务;
    		MPG模型,P调度处一个goroutine为客户端x提供服务,实际上是不同的G在为不同的client提供服务;
    		全部开协程,就变成了并发的了,同时进行请求响应。
    	2. 客户端: 端口随机,通过Socket发送请求指定到服务器端6666端口
    	 */
    
    	/*
    	服务器端代码编写: package net中
    	大部分使用者只需要Dial、Listen和Accept函数提供的基本接口,以及相关的Conn和Listener接口。
    	crypto/tls包提供了相同的接口和类似的Dial和Listen函数。
    
    	Dial函数和服务端建立连接,Listen函数创建的服务端。
    	 */
    	listener, err := net.Listen("tcp", "0.0.0.0:6666")   //返回listener为接口类型资源
    	if err != nil {
    		fmt.Println("连接错误,程序退出")  //监听都错误,后面不用玩了
    		return
    	}
    	defer listener.Close()   //类似文件,及时关闭
    	//监听成功,获得ln为&{0xc00008e000}
    	fmt.Printf("监听成功,获得lnr为%v\n",listener) //相当于监听成功就跑路了,所以需要for循环。
    	for {
    		//关于conn接口类型资源拥有的方法:
    		/*
    		// Read从连接中读取数据
    		   // Read方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
    		   Read(b []byte) (n int, err error)
    		   // Write从连接中写入数据
    		   // Write方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
    		   Write(b []byte) (n int, err error)
    		   // Close方法关闭该连接
    		   // 并会导致任何阻塞中的Read或Write方法不再阻塞并返回错误
    		   Close() error
    		   // 返回本地网络地址
    		   LocalAddr() Addr
    		   // 返回远端网络地址
    		   RemoteAddr() Addr
    		 */
    		conn, err := listener.Accept()  // Accept等待并返回下一个连接到该接口的连接, conn为接口类型实例,通俗点,通信连接线对象
    		if err != nil {
    			continue    //这里出错了不要使用return或者break,因为并发连接千万,不能因为一个就终止服务器监听
    		} else {
    			fmt.Printf("Accept() successed conn = %v\n",conn)
    			fmt.Printf("客户端IP= %v\n",conn.RemoteAddr().String())   // 返回远端网络地址
    
    		}
    		
    		//起一个协程为连接进来的客户端提供一对一服务,监听是通过服务器主程序
    		// 端口仍然是同一个,类似前台,但是提供读写等,为客户端服务的是协程
    		go recv(conn)
    	}
    }
    

    客户端Client及注释分析:

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"net"
    	"os"
    	"strings"
    )
    
    func main() {
    	//客户端使用net.Dial()来完成,无需要监听,只需要conn即可
    	conn, err := net.Dial("tcp","127.0.0.1:6666")
    	if err != nil {
    		fmt.Println("连接错误,错误原因为:",err,"请重新连接")
    		return
    	} else {
    		fmt.Println("conn is successfully connect~",conn)
    	}
    
    	reader := bufio.NewReader(os.Stdin)
    
    	for {
    		ln, err := reader.ReadString('\n')
    		if err != nil {
    			fmt.Println("Reading String Error!")
    		}
    
    
    		ln = strings.Trim(ln,"\r\n")
    		if ln == "exit" {
    			fmt.Println("客户端由于exit命令退出")
    			break
    		}
    
    		_, err = conn.Write([]byte(ln + "\n"))
    		if err != nil {
    			fmt.Println("Writing error!",err)
    		}
    	}
    }
    
    展开全文
  • JavaSE--网络编程

    2021-04-07 12:16:31
    常见的网络模型分为三种: OSI七层体系结构 TCP/IP体系结构 5层网络体系结构(教学用) 我们在此只介绍前两种网络模型 OSI七层模型 百度百科解释:OSI七层模型 应用层 网络服务与最终用户一个接口。 协议有:...
  • Java网络编程基础

    2013-10-01 15:07:22
    Java语言使用了基于套接字(Socket)的通信方式,通过系统包java.net实现三种网络通信模式:URL、Socket、Datagram(数据报)。 一、网络编程的基础知识: Internet上的计算机之间采用TCP/IP协议进行通信,其体系...
  • 为解决粗粒度密码逻辑阵列控制开销大、控制效率低问题,在研究主流阵列处理架构下层控制模型的基础上,提出了一阵列四层控制模型,并设计了对应编程控制网络。在规模为4×4编程控制网络上实现了对...
  • 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) ...
  • 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) 消息队列 IPC...
  • 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) ...
  • Linux网络编程

    2011-11-08 20:29:26
    6.2.3 套接字的三种类型............. 138 6.3 Linux 支配的网络协议..... 141 6.3.1 什么是TCP/IP? ..... 141 6.4 套接字地址.................. 142 6.4.1 什么是Socket? .... 142 6.4.2 Socket 描述符..... 142 ...
  • Java高并发网络编程

    2019-12-05 19:20:20
    分层也是一标准,为了使不同厂商计算机能够互相通信,以便在更大范围内建立计算机网络,有必要建立一个国际范围的网络体系结构标准。 ISO组织制定了OSI网络七层模型 而因特网只用到了五层 低层: ...
  • 网络编程 要素:ip、端口、协议 OSI网络层次参考模型/TCP&IP参考模型 TCP和UDP区别 基于连接和无连接 TCP要求系统资源较多,UPD较少 UDP程序结构较简单 流模式(TCP)和数据包模式(UDP) TCP保证数据正确性和...
  • BP神经网络是一神经网络学习算法,通常预先假定网络的结构已经确定,即已知计算单元层数,每层单元数目及单元之间连接,当输入输出之间是非线性关系及训练数据充足情况下,它可以出色完成不同领域问题。...
  • 本书针对网络编程初学者,面向具备C语言基础的套接字网络编程学习者,适合所有希望学习Linux和Windows网络编程的人。 第一部分主要介绍网络编程基础知识。此部分主要由Windows和Linux平台网络编程必备基础知识构成...
  • 第一章 Internet 网络编程基础知识 1 1.1 Internet网络结构 1 1.1.1 网络拓扑结构 1 1.1.2 以太网技术 3 1.1.3 其他高速网络技术 4 1.1.4 Internet整体结构 6 1.2 网络分层模型和TCP/IP协议 7 1.2.1 OSI 模型 7 ...
  • 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) ...
  • 网络协议是网络中进行数据交换与传输所需要规则、标准或约定,主要由语法(数据与信息的结构形式)、语义和同步(事件实现顺序)个要素组成。因七层模型过于复杂不实用,故简化为四层模型 地址与端口 地址就是ip...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 453
精华内容 181
关键字:

网络编程的三种模型结构