[linux network communication] one

Understand network programming and socket sockets

From the model in the figure above, we can see that the transport layer, session layer, presentation layer, and application layer should all be regarded as the main parts of network programming, and the most basic of them is the implementation of TCP and UDP protocols at the transport layer. Whether TCP or UDP protocol is implemented in the operating system, it needs to use the socket socket as a software interface for operation and realization.

Under the Linux operating system, the socket socket has a series of related system API functions. Here we briefly introduce them respectively. In the following network programming applications, these are the most basic operation interfaces. With the help of these operation interfaces, we can Realize the data transmission and application of the network program on the network.

A socket with a simple implementation of UDP and TCP

service port

/**服务端口
 
 
 */
#include <iostream>
#include <string>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>

//出错调用函数
void error_handle(std::string opt, std::string message)
{
    
    
    //根据errno值获取失败原因并打印到终端
    perror(opt.c_str());
    std::cout << message << std::endl;
    exit(1);
}

int main(int argc, char *argv[])
{
    
    
    int serv_sock;
    int client_sock;

    struct sockaddr_in serv_addr;
    struct sockaddr_in client_addr;
    //数据类型"socklen_t"和int应该具有相同的长度.否则就会破坏 BSD套接字层的填充.
    //unsigned int

    socklen_t client_addr_size;
    char message[] = "hello world";

    //判断参数数量,Usage: <port>, 需要在命令行输入服务器接收消息的端口号
    if(argc < 2)
    {
    
    
        std::cout << "Usage : " << argv[0] << " <port>" << std::endl;
        exit(1);
    }

    //创建socket 套接字
    serv_sock = socket(PF_INET, SOCK_STREAM, 0);
    if(serv_sock < 0)
    {
    
    
        error_handle("socket", "socket() error.");
    }

    //初始化套接字结构体
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//选择当前任意网卡
    serv_addr.sin_port = htons(atoi(argv[1]));//设置接收消息的端口号

    //绑定端口
    if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
    {
    
    
        error_handle("bind", "bind() error.");
    }

    //监听端口,设置等待队列数量为5
    if(listen(serv_sock, 5) < 0)
    {
    
    
        error_handle("listen", "listen() error.");
    }

    //打印输出等待连接
    std::cout << "Waiting Client...." << std::endl;

    client_addr_size = sizeof(client_addr);
    //等待接收客户端建立连接 ,链接成功会提示一个接收端口,创建一个sock
    client_sock = accept(serv_sock, (struct sockaddr*)&client_sock, &client_addr_size);
    if(client_sock < 0)
    {
    
    
        error_handle("accept", "accept() error.");
    }
    //accept() 成功建立连接后,服务器就会得到客户端的 IP 地址和端口号。
    //打印客户端 IP 和端口号
    //inet_ntoa()是编程语言,功能是将网络地址转换成“.”点隔的字符串格式。
    //ntohs()是一个函数名,作用是将一个16位数由网络字节顺序转换为主机字节顺序
    std::cout << "Client IP : " << inet_ntoa(client_addr.sin_addr) << " , port : " << ntohs(client_addr.sin_port) << std::endl;

    //向客户端发送 "hello world" 消息,使用write 标准IO接口就可以
    write(client_sock, message, sizeof(message));

    //关闭TCP连接
    close(client_sock);
    //关闭socket套接字
    close(serv_sock);

    return 0;
}

client port

/**
 * TCP/IP通信的简单实例说明
 */

#include<iostream>
#include<string>
//read,write,close
#include<unistd.h>
#include<string.h>
///某些结构体定义和宏定义,如EXIT_FAILURE、EXIT_SUCCESS等
#include<stdlib.h>
//某些函数声明,如inet_ntop()、inet_ntoa()等
#include<arpa/inet.h>
/**
与套接字相关的函数声明和结构体定义,如socket()、bind()、connect()及struct sockaddr的定义等
*/
#include<sys/socket.h>

void error_handle(std::string opt,std::string message){
    
    
    //perror ( )用 来 将 上 一 个 函 数 发 生 错 误 的 原 因 输 出 到 标 准 设备 (stderr) 。
    //参数 s 所指的字符串会先打印出,后面再加上错误原因字符串
    //c_str()生成一个const char*指针,指向以空字符终止的数组。
    perror(opt.c_str());
    std::cout<<message<<std::endl;
    //c语言返回异常终止
    exit(1);

}

int main(int argc,char* argv[]){
    
    
    int sock;
    // 端口地址输入结构体
    struct sockaddr_in serv_addr;
    //数据缓冲区
    char message[64];
    //
    int str_len;
    // 输入两个数据,一个是IP,一个是端口号
    if(argc<3){
    
    
        std::cout<<"usage:"<<argv[0]<<"<IP> <port>"<<std::endl;
        exit(1);
    }
    //设置嵌套字
    //SOCK_STREAM 是数据流,一般是tcp/ip协议的编程
    //PF_INET 代表的是ipv4
    sock = socket(PF_INET,SOCK_STREAM,0);
    //返回值可以理解为一个 id,用来标识一个 socket,如果返回 -1,说明有错误
    if(sock<0){
    
    
        error_handle("socket","socket() error.");
    }
    //memset是一个初始化函数,作用是将某一块内存中的全部设置为指定的值。
    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;//IPv4
    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);//存放地址信息
    serv_addr.sin_port = htons(atoi(argv[2]));//存放端口信息
    
    //成功则返回0,失败返回-1,错误原因存于 errno 中。

    //connect 函数只用于客户端,因为是客户端去连接。如果服务端的地址错了,或端口号错了,或服务端没有启动,connect 一定会失败。
    
    if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0){
    
    
        error_handle("connect","connect() error");
    }
    str_len = read(sock,message,sizeof(message)-1);
    if(str_len<0){
    
    
        error_handle("read","read() error");
    }
    std::cout<<"Recv Message: "<<message<<std::endl;
    
    close(sock);
    return 0;
    
}

The experimental values ​​are as follows:

port one

wpf@wpf:~/projects/unixNet$ g++ server.cpp -o server
wpf@wpf:~/projects/unixNet$ ./server 18888
Waiting Client....
Client IP : 252.127.0.0 , port : 14959

port two

wpf:~/projects/unixNet$ ./client 127.0.0.1 18888
Recv Message: hello world

Basic Logical Framework

img

img

**

Reading and writing of linux files

**

#include <iostream>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

//出错调用函数
void error_handle(std::string opt, std::string message)
{
    
    
    //根据errno值获取失败原因并打印到终端
    perror(opt.c_str());
    std::cout << message << std::endl;
    exit(1);
}

int main(int argc, char *argv[])
{
    
    
    char Hbuf[] = "Hello,";
    char Wbuf[] = ", Welcome to learn network programming!!!";
    char message[128] = {
    
    0};
    char recv_buf[64] = {
    
    0};
    int fd;
    ssize_t write_size, read_size;

    if(argc < 2 )
    {
    
    
        std::cout << "Usage : " << argv[0] << " [filename] " << std::endl;
        exit(1);
    }

    fd = open(argv[1], O_CREAT | O_TRUNC | O_RDWR);
    if(fd < 0)
    {
    
    
        error_handle("open", "open() error.");
    }

    //写入 hello
    write_size = write(fd, Hbuf, strlen(Hbuf));
    if(write_size < 0)
    {
    
    
        error_handle("write", "write() Hbuf error.");
    }

    //读取用户输入信息
    std::cout << " 请输入用户名:"  << std::endl;
    std::cin >> recv_buf;

    //写入用户名和 welcome 语句
    write_size = write(fd, recv_buf, strlen(recv_buf));
    if(write_size < 0)
    {
    
    
        error_handle("write", "write() recv_buf error.");
    }
    write_size = write(fd, Wbuf, strlen(Wbuf));
    if(write_size < 0)
    {
    
    
        error_handle("write", "write() Wbuf error.");
    }

    //关闭文件
    close(fd);

    //再次打开文件,只读模式打开
    fd = open(argv[1], O_RDONLY);
    if(fd < 0)
    {
    
    
        error_handle("open", "open() error.");
    }

    //读取文件数据,文件内容已知不足 128字节,所以使用 sizeof(message) 为长度读取能够全部将数据读取出来
    read_size = read(fd, message, sizeof(message));
    if(read_size < 0)
    {
    
    
        error_handle("read", "read() message error.");
    }

    //将读取数据打印输出
    std::cout << " 从文件中读取到 " << read_size << " 个字节的数据." << std::endl;
    std::cout << message << std::endl;

    //最后关闭文件
    close(fd);

    return 0;
}

Guess you like

Origin blog.csdn.net/Android_WPF/article/details/126211481