柳大的Linux讲义·基础篇(4)网络编程基础

本文是柳大关于Linux网络编程基础的讲解,涵盖了TCP和UDP的C/S模型,包括TCP Server和Client的创建、连接、数据收发及关闭,以及UDP Server和Client的发送和接收数据。文章还探讨了TCP与UDP的区别,强调了裸用socket的性能问题,并预告了后续将介绍的IO复用技术。
摘要由CSDN通过智能技术生成

柳大的Linux游记·基础篇(4)网络编程基础

  • Author: 柳大·Poechant
  • Blog: Blog.CSDN.net/Poechant
  • Email:zhongchao.usytc#gmail.com (#->@)
  • Date:March 11th, 2012
  • Copyright © 柳大·Poechant(钟超·Michael)

回顾

  1. 《柳大的Linux游记·基础篇(1)磁盘与文件系统》
  2. 《柳大的Linux游记·基础篇(2)Linux文件系统的inode》
  3. 《柳大的Linux游记·基础篇(3)权限、链接与权限管理》

闲话

最近很忙,博文写的少。感谢一些博友的理解。

有博友发邮件说《柳大的Linux游记》希望继续写下去,希望了解一些与 socket 入门有关的内容。对此深表惭愧,当时也是应一个博友的来信而开始写这个系列的,但仅写了三篇就没继续了。与 socket 相关的文章,在网络上非常多,socket 编程也是基本功。要我来写的话,写出心意很难,我只希望能写系统一些,所以我想先介绍 socket 的基础,然后说说 select,poll 和 epoll 等 IO 复用技术,可能这样会系统一些,也更实用。

W. Richard Stevens 的 UNIX Network Programming Volume 1 中讲解例子的时候都使用了include "unp.h",这是 Stevens 先生在随书源码中的提供的一个包含了所有 UNIX 网络编程会用到的头文件的的一个头文件。但这样对于不了解 UNIX 网络编程以及 socket 的朋友来说,并不是一个好的学习途径。所以我想看完本文后读 Stevens 先生的杰出作品更好一些 :)

另外,《JVM深入笔记》的第四篇正在整理,最近确实空闲时间比较少,对此感到很抱歉。我会尽量抽时间多分享一些的。

言归正传,下面还是沿袭我的一贯风格,先以最简单的实例开始。

目录

  1. 快速开始
    • 1.1 TCP C/S
      • 1.1.1 TCP Server
      • 1.1.2 TCP Client
    • 1.2. UCP C/S
      • 1.2.1 UDP Server
      • 1.2.2 UDP Client
  2. TCP 和 UCP 的 Socket 编程对比
    • 2.1 Server
    • 2.2 Client
    • 2.3 所使用的 API 对比
  3. 裸用 socket 的性能很差

1 快速开始

1.1 TCP C/S

无论你是使用 Windows 还是 UNIX-like 的系统,操作系统提供给应用层的网络编程接口都是 Socket。在 5 层的 TCP/IP 网络结构或者 7 层的 OSI 网络结构中,都有传输层,TCP 和 UDP 协议就是为传输层服务的。而网络层的最常用协议就是 IP(IPv4 或 IPv6)在高层编写程序,就需要用到 TCP 协议和 UDP 协议。其直接使用,就是通过 Socket 来实现的。

先看一段简单的 TCP 通信的 Server 与 Client 例程。

1.1.1 TCP Server

下面是一个 TCP 连接的 Server 实例。

#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    // Get Port option
    if (argc < 2)
    {
        fprintf(stderr, "ERROR, no port provided\n");
        exit(1);
    }
    int port_no = atoi(argv[1]);

    // Get socket
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);

    // Bind
    struct sockaddr_in server_addr;
    bzero((char *) &server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(port_no);
    bind(socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));

    // Listen
    listen(socket_fd, 5);

    while (1) {

        // Accept
        struct sockaddr_in client_addr;
        socklen_t client_addr_length = sizeof(client_addr);
        int socket_to_client = accept(socket_fd, (struct sockaddr *) &client_addr, &client_addr_length);

        // Read
        char buffer[1024];
        bzero(buffer, sizeof(buffer));
        read(socket_to_client, buffer, sizeof(buffer) - 1);
        printf("Here is the message: %s\n", buffer);

        // Write
        const char *data = "I got your message.";
        write(socket_to_client, data, sizeof(data));

        // Close
        close(socket_to_client);
    }

    close(socket_fd);

    return 0;
}

上面是 TCP 的 Client 的 Simplest Example。概括起来 Scoket Server 编程有如下几个步骤:

1.1.1.1 获取 Socket Descriptor:
    // socket function is included in sys/socket.h
    // AF_INET is included in sys/socket.h
    // SOCK_STREAM is included in sys/socket.h
    socket(AF_INET, SOCK_STREAM, 0);

通过sys/socket.h中的socket函数。第一个参数表示使用IPv4 Internet Protocol,如果是AF_INET6则表示IPv6 Internet Protocol,其中AF表示Address Family,另外还有PF表示Protocol Family。第二个参数表示流传输Socket Stream,流传输是序列化的、可靠的、双向的、面向连接的,Kernel.org 给出的解释是:“Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission mechanism may be supported.”

另外一个常用的是SOCK_DGRAM表示Socket Diagram,是无连接的、不可靠的传输方式,Kernel.org 给出的解释是“Supports datagrams (connectionless, unreliable messages of a fixed maximum length).”

第三个参数表示使用的协议族中的哪个协议。一般来说一个协议族经常只有一个协议,所以长使用“0”。具体参见Kernel.org 给出的解释

1.1.1.2 绑定地址与端口

首先要创建一个struct sockaddr_in,并设置地址族、监听的外来地址与本地端口号。如下:

// struct sockaddr_in is inclued in netinet/in.h
// bzero function is included in string.h
// atoi is include in stdlib.h
struct sockaddr_in server_addr;
bzero((char *) &server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(atoi(argv[1]))

然后将第 1 步创建的Socket与这里创建的地址绑定(实际上直接用的是Socket Descriptor)。


                
  • 8
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钟超

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值