网络编程-TCP

网络通信基础

1、网络通信的协议:TCPUDPIP

2、网络通信模型:七层模型、四层模型

3、网络通信理论:socketIP、端口号、字节序

4、网络IO模型:4种

5、网络超时处理

6、网络的广播、组播、单播

网络通信的特征

(局域网)不同设备在通信时,要求其IP地址必须处于同一网段

网络通信协议
TCP\IP

(传输控制协议\因特网互联协议)

TCP:主要是数据发送数据时,若出现数据发送失败,可控制进行重新发送

IP:用于通信过程的IP地址

UDP

(用户数据报协议)

UDP:没有数据重发机制

TCPUDP
可靠通信不可靠通信
通信效率低通信效率高
面向连接面向非连接
网络通信模型
七层模型四层模型
应用层领导口述一段话
表示层秘书记录口述内容形成信件
会话层将信件放在公司前台应用层领导自己写信放置前台
传输层快递员从前台取件传输层快递员从前台取件
网络层分拣快递理清发送地址网络层分拣快递理清发送地址
数据链路层快递传输过程
物理层将信件送至收件人网络链路层投送快递到收件人
网络通信理论

socket:套接字,特殊的文件描述符,不允许使用open打开

IP:当前所用的IP地址都是32位的点分式,用于区分设备

端口号:2字节的短整型(1~65535)自己写的程序中端口号一般设置大于10000即可,用于区分应用

字节序:在x86体系下,操作系统一般是小端存储模式,对于网络通信一般是大端存储模式

网络通信高级

TCP通信流程
客户端服务器
保证有一台手机int cfd = socket保证有一台手机int sdf = socket
拨打号码connect(cfd)需要绑定一个手机号bind(sfd)
畅聊,相当于收发数据send(cfd)设定手机铃声,用于监视listen(sfd)
挂断电话close(cfd)等待来电,等待客户端连接请求int cfd = accept(sfd)
畅聊,相当于收发数据recv(cfd)
挂断电话close(cfd)close(sfd)
//实现一个客户端给服务器发送 服务器负责接收
//head.h
#ifndef _HEAD_H
#define _HEAD_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#endif 
//服务端
// ./server 1277.0.0.1 10001
int main(int argc, char* argv[])
{
    // 参数1:代表IPV4
    // 参数2:代表TCP
    // 参数3:默认为0,一般不用
    // 返回值:返回服务端的套接字,失败返回-1
    
    // 1、创建套接字
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sfd < 0)
    {
        perror("socket error");
        return -1;
    }
    // 知道创建操作完成
    printf("socket success\n");
    
    // 2、服务端绑定IP地址和端口号
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;	// 地址族IPV4
    addr.sin_port = atoi(argv[2]);	// 设置端口号
    // 将字符串形式的IP地址直接转换成网络地址
    int ret = inet_pton(AF_INET, argv[1], (struct in_addr*)&addr.sin_addr);
    if(ret <= 0)
    {
        perror("inet_pton error");
        return -1;
    }
    
    ret = bind(sfd, (struct sockaddr*)&addr, sizeof(addr));
    if(ret < 0)
    {
        perror("bind error\n");
        return -1;
    }
    // 知道绑定操作完成
    printf("bind success\n");
    
    //3、实现监听操作
    ret = listen(sfd, 2);
    if(ret < 0)
    {
        perror("listen error");
        return -1;
    }
    //知道监听完成
    printf("listen success\n");
    
    //4、等待客户端的连接请求
    struct sockaddr_in cld_addr;	//出参:待会连接客户端的IP端口号
    int len = sizeof(cld_addr);
    
    int cfd = accept(sfd, (struct sockaddr*)&cld_addr, &len);
    if(cfd < 0)
    {
        perror("accept error");
        return -1;
    }
    //知道连接完成
    printf("accept success!\n");
    
    //5、接收客户端的数据
    char buf[100];
    while(1)
    {
        bzero(buf, sizeof(buf));
    	recv(cfd, buf, sizeof(buf)-1, 0);
        
        if(strstr(buf, "quit") != NULL)
        {
            break;
        }
        printf("from %d info is:%s\n", cfd, buf);
    }
    
    //6、关闭套接字
    close(cfd);
    close(sfd);
    
    printf("server closed!\n");
    
    return 0;
}


//客户端
// ./client 127.0.0.1 10001
int main(int argc, char* argv[])
{
    // 1、创建套接字
    int cfd = socket(AF_INET, SOCK_STREAM, 0);
    if(cfd < 0)
    {
        perror("socket error");
        return -1;
    }
    // 知道创建操作完成
    printf("socket success\n");
    
    // 2、向服务端发送连接申请
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;	// 地址族IPV4
    addr.sin_port = atoi(argv[2]);	// 设置端口号
    // 将字符串形式的IP地址直接转换成网络地址
    int ret = inet_pton(AF_INET, argv[1], (struct in_addr*)&addr.sin_addr);
    if(ret <= 0)
    {
        perror("inet_pton error");
        return -1;
    }
    
    ret = connect(cfd, (struct sockaddr*)&addr, sizeof(addr));
    if(ret < 0)
    {
        perror("connect error\n");
        return -1;
    }
    // 知道绑定操作完成
    printf("connect success\n");
    
    //3、向服务端的数据
    char buf[100];
    
    while(1)
    {
        bzero(buf, sizeof(buf));
        fgets(buf, sizeof(buf), stdin);
    	send(cfd, buf, sizeof(buf)-1, 0);
        
        if(strstr(buf, "quit") != NULL)
        {
            break;
        }
    }
    
    close(cfd);
    
    printf("client closed!\n");
    
    return 0;
}
//实现多个客户端给服务端发送请求
//服务端
// ./server 1277.0.0.1 10001

void* handle_client(void* arg)
{
    int cfd = *((int*)arg);

    /* 5、接收客户端的数据 */
    char buf[100];

    while(1)
    {
        bzero(buf, sizeof(buf));
        recv(cfd, buf, sizeof(buf)-1, 0);

        if (strstr(buf, "quit") != NULL)
        {
            printf("client [%d] is quit!\n", cfd);
            close(cfd);
            pthread_exit(NULL);
        }

        if (strlen(buf) != 0)
        {
            printf("from %d info is: %s\n", cfd, buf);
        }
    }

}

// ./server 127.0.0.1 10001
int main(int argc,char *argv[])
{
    /* 1、创建套接字 */
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sfd < 0)
    {
        perror("socket error");
        return -1;
    }

    printf("socket success!\n");


    /* 2、服务端绑定IP地址和端口号 */
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;      // 地址簇IPV4
    addr.sin_port = atoi(argv[2]);  // 设置端口号

    // 将字符串形式的IP地址,直接转换为网络地址
    int ret = inet_pton(AF_INET, argv[1], (struct in_addr*)&addr.sin_addr);
    if (ret <= 0)
    {
        perror("inet_pton error");
        return -1;
    }

    ret = bind(sfd, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0)
    {
        perror("bind error!\n");
        return -1;
    }

    printf("bind success!\n");


    /* 3、实现监听操作 */
    ret = listen(sfd, 5);
    if (ret < 0)
    {
        perror("listen error!\n");
        return -1;
    }

    printf("listen success!\n");


    /* 4、等待客户端的连接请求 */
    struct sockaddr_in cld_addr; // 出参: 带回连接客户端的IP和端口号
    int len = sizeof(cld_addr);

    
    // 主循环,接受客户端连接
    int cfd;
    pthread_t thread_id;
    while (1) 
    {
        cfd = accept(sfd, (struct sockaddr *)&cld_addr, &len);
        if (cfd < 0)
        {
            // 当前客户端请求失败后,只报错,不能退出程序
            // 因为其他进程还要进行连接。
            perror("accept error!\n");
        }
        else
        {
            // 连接请求成功后,在多线程中进行读写操作
            printf("client socket = [%d]: accept success!\n", cfd);
            if (pthread_create(&thread_id, NULL, handle_client, (void*)&cfd) != 0) 
            {
                // 如果线程创建失败表明无法与客户端实现数据通信,则将客户端的套接字关闭。
                printf("client socket = [%d]: could not create thread: %s\n", cfd, strerror(errno));
                close(cfd);
            }
        }

        // 分离线程,让线程自主运行

        pthread_detach(thread_id);
    }


    /* 6、关闭套接字 */
    // 这个一般执行不到,因为服务端需要一值运行
    close(cfd);
    close(sfd);

    printf("server closed!\n");

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值