IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 进城编程、TCP、UDP网络编程及工作原理详解 -> 正文阅读

[网络协议]进城编程、TCP、UDP网络编程及工作原理详解

第一部分:进程编程基础及TCP网络编程

  1. 利用Linux环境中的fork函数来进行进程编程,以产生子进程。

fork函数的工作原理:

fork()系统调用通过复制一个现有进程来创建一个全新的进程。进程被存放在一个叫做任务队列的双向循环链表当中,链表当中的每一项都是类型为task_struct称为进程描述符的结构,也就是我们写过的进程PCB.内核通过一个位置的进程标识值或PID来标识每一个进程。//最大值默认为32768,short int短整型的最大值.,他就是系统中允许同时存在的进程最大的数目。

可以到目录 /proc/sys/kernel中查看pid_max:

当进程调用fork后,当控制转移到内核中的fork代码后,内核会做4件事情:

1、分配新的内存块和内核数据结构给子进程

2、将父进程部分数据结构内容拷贝至子进程

3、添加子进程到系统进程列表当中

4、fork返回,开始调度器调度

函数功能:

以当前进程作为父进程创建出一个新的子进程,并且将父进程的所有资源拷贝给子进程,这样子进程作为父进程的一个副本存在。父子进程几乎时完全相同的,但也有不同的如父子进程ID不同。当fork系统调用成功时,它会返回两个值:一个是0,另一个是所创建的新的子进程的ID(>0)。当fork成功调用后此时有两个数据相同的父子进程,我们可以通过fork的返回值来判断接下来程序是在执行父进程还是子进程。id==0:执行子进程 id>0:在父进程中执行 id<0:fork函数调用失败

代码:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void main(){

    pid_t child_pid;
    child_pid = fork();
    if(child_pid==0)
    {
            printf("I am the child procress,my pid is %d\n",getpid());
    }
    if(child_pid>0)
    {
        printf("I am the parent process,my pid is %d\n",getppid());
    }
}

效果:

进行基本的TCP网络编程,理解其编程框架的基本原理和工作过程。

工作过程和原理:

服务器端整个程序的工作过程:

socket()—>bind()—>listen()—>accept()—>read()—>write()—>close()

1.首先服务器端创建socket,以及服务器和客户端的地址信息初始化;

2.再通过bind函数把socket和服务端地址绑定;

3.然后服务器开始使用listen函数进行监听;

4.监听成功后,使用accept函数接受监听内容;

5.创建子进程读取消息内容(read函数),父进程继续监听listen函数;

6.服务器对收到的消息进行处理,用write函数给客户端发出一个回应消息;

7.关闭socket

客户端整个工作过程

socket()—>connect()—>write()—>read()—>close()

1.首先创建socket,以及服务器地址信息初始化;

2.connect()函数与服务器进行TCP三次握手连接;

3.用write()函数给服务器发送消息;

4.接收服务器端的回应消息read();

5.关闭socket,close()。

socket函数(客户端、服务器端函数)

功能:在调用socket的一方打开一个套接口,相当于打开一个文件,返回值为文件描述符。

注意:socket是在本地创建一个套接口,通信双方都需要创建各自的套接口,通信双方就是通过这个套接口进行数据交换的。

bind函数(服务器端函数)

功能:bind函数是将一个计算机上的套接口与自己的某个地址绑定起来,以使得在后期如果某个程序想要与这个地址所代表的服务通信时直接使用通过与这个服务绑定的socket交换数据。也就是说通过bind函数将本机上的某个服务与socket描述符绑定起来,以后访问该服务等都是通过这个套接口交换数据的。

注意:通常情况下TCP通信的客户端不是必须调用bind函数(可以调用也可以不调用),在TCP服务器端必须调用bind函数。bind函数的功能是将本地的socket与本地标示某一个服务的地址绑定在一起,以便后续通过套接口来与服务交换数据。

connect函数(客户端函数)

功能:bind函数将本地的sockfd与本地主机的地址绑定在一起了。connect函数是本地的sockfd与服务器端的地址(server_addr)发起连接请求。connect就是三次握手与服务器端建立TCP连接的一个过程。connect函数是在客户端调用的,服务器端不用调用connect函数。

注意:如果connect函数调用失败,随之这个套接口(sockfd)也会失效,我们必须使用close函数将sockfd关闭。如果接下来我们想要重新调用connect函数就必须调用socket函数,重新打开一个新的sockfd。

listen函数(服务器端函数)

功能:listen函数的功能就是监听想要使用套接字描述符sockfd所绑定服务的请求。因为我们在listen之前已经使用bind函数将套接口描述符与一个服务的地址绑定在一起,所以可以监听这个套接字描述符就相当于对该服务的请求的监听。

accept函数(服务器端函数)

功能:从连接请求队列中获取第一个连接请求。(当队列中没有请求的话,如果套接口为阻塞方式的话,accpet函数会阻塞直到有新的连接请求到来;如果套接口为非阻塞方式的话,accept函数返回错误代码)并且处理这个请求返回一个新的连接套接字,后续使用这个新的套接字进行数据的发送与接收。

注意:1. accept函数的返回值是一个新的套接字,建立连接以后使用这个新的套接字进行数据发送与接收。以前的那个套接字仍然处于监听状态;

?????????? 2. accept函数的第二个和第三个参数使用来被填充的。用来获取调用connect的客户端的信息。如果不需要这些信息,可以把这个两个参数设置为NULL;

?????????? 3. 如果请求连接队列中没有“连接请求”了,那么accpet函数会议阻塞方式等待连接请求的到来;如果连接请求队列为空且sockfd是非阻塞方式的话,accpet函数就会返回一个错误信息

效果:

代码:

Server.c

#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>

void main()
{
        /*1 creat socket */
        pid_t pid;
        int socket_fd,accept_fd;
        int addrlen,iBytes;
        unsigned char buf[256];
        struct sockaddr_in server,client;

        if((socket_fd=socket(AF_INET,SOCK_STREAM,0))== -1)
        {
                perror("Error--socket:");
                _exit(-1);
        }

        bzero(&server,sizeof(server));
        server.sin_family=AF_INET;

        server.sin_port=htons(4000);
        server.sin_addr.s_addr=htonl(INADDR_ANY);

        if(bind(socket_fd,(struct sockaddr *)&server,sizeof(server))==-1)
        {
                perror("Error--bind:");
                _exit(-2);
        }

        if(listen(socket_fd,5)==-1)
        {
                perror("Error--listen:");
                _exit(-3);
        }

        addrlen=sizeof(client);
        for(;;){
                if((accept_fd=accept(socket_fd,(struct sockaddr *)&client,&addrlen))==-1)
                {
       perror("Error--listen:");
                        _exit(-4);
                }

                pid =fork();
                if(pid>0)continue;
                else if(pid==-1){
                        perror("Error--listen:");
                        _exit(-5);
                }

                 bzero(buf,256);
                iBytes=read(accept_fd,buf,256);
                if(iBytes==-1){
                        perror("Error--fork:");
                        _exit(-6);
                }

                printf("[ %s: %d]send a connection request: %s\n ",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);
                if(write(accept_fd,"Welcome,baby!\n",15)==-1)
                {
                        perror("Error--fork:");
                        _exit(-7);
                }

                close(accept_fd);
                _exit(0);

        }
        printf("call back:%s\n",buf);
        close(socket_fd);
        _exit(0);

}

Client.c

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

main()
{
        int socket_fd;
        int addrlen,iBytes;
        unsigned char buf[256];
        struct sockaddr_in server;

        if((socket_fd=socket(AF_INET,SOCK_STREAM,0))==-1)
        {
                perror("Error--socket:");
                _exit(-1);
        }

        bzero(&server,sizeof(server));
        server.sin_family=AF_INET;
        server.sin_port=htons(4000);

        server.sin_addr.s_addr=inet_addr("192.168.37.129");
        if(connect(socket_fd,(struct sockaddr *)&server,sizeof(server))==-1)
        {
                perror("Error--connect:");
                _exit(-2);
        }

        if(write(socket_fd,"hi,i am guangzhou!\n",17)==-1)
        {
                perror("Error--write:");
                _exit(-3);
        }

        bzero(buf,256);
        iBytes=read(socket_fd,buf,256);
        if(iBytes==-1)
        {
                perror("Error--read:");
                _exit(-4);
        }
        printf("call back:%s\n",buf);
        close(socket_fd);
        _exit(0);
}


第二部分:UDP网络编程

进行基本的UDP网络编程,理解其编程框架的基本原理和工作过程。

工作过程和原理:

服务器端整个程序的工作过程

(1)建立套接字文件描述符,使用函数socket(),生成套接字文件描述符。

(2)设置服务器地址和侦听端口,初始化要绑定的网络地址结构。

(3)绑定侦听端口,使用bind()函数,将套接字文件描述符和一个地址类型变量进行绑定。

(4)接收客户端的数据,使用recvfrom()函数接收客户端的网络数据。

(5)向客户端发送数据,使用sendto()函数向服务器主机发送数据。

(6)关闭套接字,使用close()函数释放资源。UDP协议的客户端流程

客户端整个工作过程

(1)建立套接字文件描述符,socket();

(2)设置服务器地址和端口,struct sockaddr;

(3)向服务器发送数据,sendto();

(4)接收服务器的数据,recvfrom();

(5)关闭套接字,close()。
socket函数(客户端、服务器端函数)

功能:在调用socket的一方打开一个套接口,相当于打开一个文件,返回值为文件描述符。

注意:socket是在本地创建一个套接口,通信双方都需要创建各自的套接口,通信双方就是通过这个套接口进行数据交换的。

bind函数(服务器端函数)

功能:bind函数是将一个计算机上的套接口与自己的某个地址绑定起来,以使得在后期如果某个程序想要与这个地址所代表的服务通信时直接使用通过与这个服务绑定的socket交换数据。也就是说通过bind函数将本机上的某个服务与socket描述符绑定起来,以后访问该服务等都是通过这个套接口交换数据的。

注意:通常情况下TCP通信的客户端不是必须调用bind函数(可以调用也可以不调用),在TCP服务器端必须调用bind函数。bind函数的功能是将本地的socket与本地标示某一个服务的地址绑定在一起,以便后续通过套接口来与服务交换数据。

sendto函数(客户端、服务器端函数)

功能:基于UDP发送数据报,返回实际发送的数据长度,出错时返回-1

recvfrom函数(客户端、服务器端函数)

功能:从UDP接收数据,返回实际接收的字节数,失败时返回-1

效果:

代码:

Server.c

#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>

void main()
{
        int socket_fdu;
        int recv_num;
        int send_num;
        int client_len;
        char recv_buf[20];
        struct sockaddr_in addr_server;
        struct sockaddr_in addr_client;

        if((socket_fdu=socket(AF_INET,SOCK_DGRAM,0))==-1)
        {
                perror("Error--socket:");
                _exit(1);
        }

        memset(&addr_server,0,sizeof(struct sockaddr_in));
        addr_server.sin_family=AF_INET;
        addr_server.sin_port=htons(4001);
        addr_server.sin_addr.s_addr=htonl(INADDR_ANY);

        client_len=sizeof(struct sockaddr_in);

        if(bind(socket_fdu,(struct sockaddr *)&addr_server,sizeof(struct sockaddr_in))<0)
        {
                perror("Error--bind:");
                _exit(1);
        }

        while(1)
        {
                recv_num=recvfrom(socket_fdu,recv_buf,sizeof(recv_buf),0,\
                                (struct sockaddr *)&addr_client,&client_len);
                if(recv_num<0)
                {
                        perror("recvform again");
        				_exit(1);
                }
                else{
                        recv_buf[recv_num]='\0';
                        printf("receive success:%s\n",recv_buf);
                }

                send_num = sendto(socket_fdu,recv_buf,recv_num,0,\
                                (struct sockaddr *)&addr_client,client_len);
                if(send_num<0)
                {
                        perror("Error--sendto:");
                        _exit(1);
                }
        }
        close(socket_fdu);
}

Client.c

#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<netdb.h>
#include<errno.h>


void main()
{
        struct sockaddr_in server_addr;
        bzero(&server_addr,sizeof(server_addr));
        server_addr.sin_family =AF_INET;
        server_addr.sin_addr.s_addr=inet_addr("192.168.37.129");
        server_addr.sin_port=htons(4001);

        int client_socket_fd =socket(AF_INET,SOCK_DGRAM,0);
        if(client_socket_fd<0)
        {
                perror("creat socket failed:");
                _exit(1);
        }

        if(sendto(client_socket_fd,"Hello,there!",13,0,\
                                (struct sockaddr *)&server_addr,sizeof(server_addr))<0)
        {
                perror("sendto failed:");
                _exit(1);
        }

        close(client_socket_fd);
}

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-11-28 11:37:38  更:2021-11-28 11:38:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:02:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码