《3.linux应用编程和网络编程-第9部分-3.9.linux网络编程实践》3.9.6_7.soekct实践编程1_2

概念:端口号,实质就是一个数字编号,用来在我们一台主机中(主机的操作系统中)唯一的标识一个能上网的进程端口号和IP地址一起会被打包到当前进程发出或者接收到的每一个数据包中。每一个数据包将来在网络上传递的时候,内部都包含了发送方和接收方的信息(就是IP地址和端口号),所以IP地址和端口号这两个往往是打包在一起不分家的。

IP 地址用来精确到 那一台 电脑

端口号:用来 精确 到这一台 电脑 某一个进程

3.9.6.1、服务器端程序编写
(1)socket : 建立一个网络连接
(2)bind : 把我当前的 IP 地址 和 端口号  和 socket 绑定起来 
(3)listen : 监听
(4)accept,返回值是一个fd,accept正确返回就表示我们已经和前来连接我的客户端之间建立了一个TCP连接了,以后我们就要通过这个连接来和客户端进行读写操作,读写操作就需要一个fd,这个fd就由accept来返回了。
注意:socket返回的fd叫做监听fd,是用来监听客户端的,不能用来和任何客户端进行读写accept返回的fd叫做连接fd,用来和连接那端的客户端程序进行读写。
 

3.9.9.socket编程实践4
3.9.9.1、自定义应用层协议第一步:规定发送和接收方法
(1)规定连接建立后由客户端主动向服务器发出1个请求数据包,然后服务器收到数据包后回复客户端一个回应数据包,这就是一个通信回合
(2)整个连接的通信就是由N多个回合组成的。

程序 有两个 .c 文件 服务器程序server.c  ,  和 客户端 程序 client.c

服务器程序server.c 

#include <stdio.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>#define SERPORT 6003
#define SERADDR "192.168.80.128 " /* 我的电脑做服务器  ubuntu 下 ifconfig 得到的 IP地址 */
#define BACKLOG 10char recvbuf[100]={0};int main(void)
{int sockfd = -1;  /* 定义一个接收 socket 文件描述符(socket 的返回值) */int ret = -1;/* 定义一个接收 bind (bind 的返回值) */int clifd = -1;  /* 定义一个接收 accept (accept的返回值) */struct sockaddr_in seraddr = {0}; /* 定义一个bind 第二个参数(输入型参数) 这个结构体是网络编程接口中用来表示一个IP地址的 */struct sockaddr_in cliaddr = {0}; /* 定义一个accept 第二个参数(输出型参数) 这个结构体是网络编程接口中用来表示一个IP地址的 */socklen_t len = 0;/* 1 . 先 socket  打开文件描述符 */sockfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == sockfd){perror("socket");return -1;}printf("sockfd = %d \n", sockfd);/* 2 . bind 绑定sockfd 和当前电脑的 IP地址 和端口号 */seraddr.sin_family = AF_INET;  /* 设置 地址族为 IPV4 */seraddr.sin_port = htons(SERPORT);           /* 服务器端口号  htons 当前电脑 字节序 转成 网络 字节序 16位 */seraddr.sin_addr.s_addr = inet_addr(SERADDR);   /* 设置 IP地址 */ret = bind(sockfd, (const struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){perror("bind");return -1;}printf("bind success \n");/* 3 .  listen ,监听 端口号 */ret = listen(sockfd, BACKLOG); if(ret < 0){perror("listen");return -1;}printf("服务器开始监听 \n");/* 4 .  accept 阻塞等待 客服端来连接服务器 */	clifd = accept(sockfd,(struct sockaddr *)&cliaddr,  &len);/* 阻塞等待 客服端来连接服务器  */printf("客户端 已连接服务器 clifd = %d \n",clifd);  /*accept返回的fd叫做连接fd,用来和连接那端的客户端程序进行 读写。 *//* 5 .  建立连接后 就可以通讯了 */	
#if 0ret = recv(clifd, recvbuf,sizeof(recvbuf),0); /* recv 接收出错会返回 -1 */	printf("成功接收了 %d 个字节\n",ret);printf("client发送的内容是 %s  \n",recvbuf);
#endifwhile(1){/* 1.回合第一步, 服务器接收 */	ret = recv(clifd, recvbuf,sizeof(recvbuf),0); /* recv 接收出错会返回 -1 */	printf("client发送的内容是 %s  \n",recvbuf);memset(recvbuf,0,sizeof(recvbuf));/* 2.服务器机箱客户 数据包 */	/* 3.回合第三步, 回复客户端  */ret = send(clifd, "ok",2,0); /* recv 接收出错会返回 -1 */	}return 0;
}/*************************************************************
3.9.4.5、表示IP地址相关数据结构
(1)都定义在 netinet/in.h
(2)struct sockaddr,这个结构体是网络编程接口中用来表示一个IP地址的,注意这个IP地址是不区分IPv4和IPv6的(或者说是兼容IPv4和IPv6的)
(3)typedef uint32_t in_addr_t;		网络内部用来表示IP地址的类型
(4)struct in_addr{in_addr_t s_addr;};
(5)struct sockaddr_in{__SOCKADDR_COMMON (sin_);    宏定义 :这个是看 是IPV4 还是 IPV6  in_port_t sin_port;                   端口号struct in_addr sin_addr;          	IP地址unsigned char sin_zero[sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)];};
(6)struct sockaddr			这个结构体是linux的网络编程接口中用来表示IP地址的标准结构体,bind、connect等函数中都需要这个结构体,这个结构体是兼容IPV4和IPV6的。在实际编程中这个结构体会被一个struct sockaddr_in或者一个struct sockaddr_in6所填充。const struct sockaddr *address 就等同于  struct sockaddr_in*******************************************************************/

客户端 程序 client.c

#include <stdio.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>/* 客户端端口 号 可以自己分配的,只有 和 服务器的 端口号 一直才能连接上 服务器 */#define SERADDR  "192.168.80.128 " /* 服务器给我们 开放的 IP 地址 和 端口号 */
#define SERPORT  6003
#define BACKLOG 10char sendbuf[100]={0};
char recvbuf[100];int main(void)
{int sockfd = -1;  /* 定义一个接收 socket 文件描述符(socket 的返回值) */int ret = -1;/* 定义一个接收 bind (bind 的返回值) */struct sockaddr_in seraddr = {0}; /* 定义一个connect 第二个参数(输入型参数) 这个结构体是网络编程接口中用来表示一个IP地址的 *//* 1 . 先 socket  打开文件描述符 */sockfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == sockfd){perror("socket");return -1;}printf("sockfd = %d \n", sockfd);/* 2. connect  */seraddr.sin_family = AF_INET;  /* 设置 地址族为 IPV4 */seraddr.sin_port = htons(SERPORT);           /* 服务器端口号  htons 当前电脑 字节序 转成 网络 字节序 16位 */seraddr.sin_addr.s_addr = inet_addr(SERADDR);   /* 设置 IP地址 */ret = connect(sockfd,(const struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){perror("connect");return -1;}printf("成功建立连接 \n");/*  建立连接后 就可以通讯了 */	
#if 0	strcpy(sendbuf,"hello world");ret = send(sockfd,sendbuf,strlen(sendbuf), 0);printf("发送了 %d 个字符 \n",ret);
#endifwhile(1){/*  1. 客户端 首先给服务器 发送数据包 */	printf("请输入要发送的内容\n");scanf("%s",sendbuf);//printf("刚才输入的是 %s \n",sendbuf);ret = send(sockfd,sendbuf,strlen(sendbuf), 0);printf("发送了多少个字节 %d \n",ret);/* 2.回合第2步,客户端 接收 服务器的回复  */memset(recvbuf,0,sizeof(recvbuf));	ret = recv(sockfd, recvbuf,sizeof(recvbuf),0); /* recv 接收出错会返回 -1 */	printf("接收到服务器 发送的内容是 %s  \n",recvbuf);/* 3.回合第3步,客户端 解析 服务器的回复,在做下一步定夺  */}return 0;
}

make 

all:gcc server.c -o sergcc client.c -o cliclean:rm ser cli *.o -rf

运行结果:

 

 

3.9.9.2、自定义应用层协议第二步:定义数据包格式

服务器程序server.c 

#include <stdio.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>#define SERPORT 6003
#define SERADDR "192.168.80.128 " /* 我的电脑做服务器  ubuntu 下 ifconfig 得到的 IP地址 */
#define BACKLOG 10char recvbuf[100]={0};#define CMD_REGISTER  1001 /*注册学生信息 */
#define CMD_CHECK     1002  /*检查 学生信息 */
#define CMD_GETINFO   1003  /*获取 学生信息 */#define STAT_OK    30
#define STAT_ERR   31typedef struct commu
{char name[20]; /* 学生姓名 */int age;  /* 学生年龄 */int cmd; /*命令码*/int stat; /*状态信息, */}info;int main(void)
{int sockfd = -1;  /* 定义一个接收 socket 文件描述符(socket 的返回值) */int ret = -1;/* 定义一个接收 bind (bind 的返回值) */int clifd = -1;  /* 定义一个接收 accept (accept的返回值) */struct sockaddr_in seraddr = {0}; /* 定义一个bind 第二个参数(输入型参数) 这个结构体是网络编程接口中用来表示一个IP地址的 */struct sockaddr_in cliaddr = {0}; /* 定义一个accept 第二个参数(输出型参数) 这个结构体是网络编程接口中用来表示一个IP地址的 */socklen_t len = 0;/* 1 . 先 socket  打开文件描述符 */sockfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == sockfd){perror("socket");return -1;}printf("sockfd = %d \n", sockfd);/* 2 . bind 绑定sockfd 和当前电脑的 IP地址 和端口号 */seraddr.sin_family = AF_INET;  /* 设置 地址族为 IPV4 */seraddr.sin_port = htons(SERPORT);           /* 服务器端口号  htons 当前电脑 字节序 转成 网络 字节序 16位 */seraddr.sin_addr.s_addr = inet_addr(SERADDR);   /* 设置 IP地址 */ret = bind(sockfd, (const struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){perror("bind");return -1;}printf("bind success \n");/* 3 .  listen ,监听 端口号 */ret = listen(sockfd, BACKLOG); if(ret < 0){perror("listen");return -1;}printf("服务器开始监听 \n");/* 4 .  accept 阻塞等待 客服端来连接服务器 */	clifd = accept(sockfd,(struct sockaddr *)&cliaddr,  &len);/* 阻塞等待 客服端来连接服务器  */printf("客户端 已连接服务器 clifd = %d \n",clifd);  /*accept返回的fd叫做连接fd,用来和连接那端的客户端程序进行 读写。 *//* 5 .  建立连接后 就可以通讯了 */	
#if 0ret = recv(clifd, recvbuf,sizeof(recvbuf),0); /* recv 接收出错会返回 -1 */	printf("成功接收了 %d 个字节\n",ret);printf("client发送的内容是 %s  \n",recvbuf);
#endifwhile(1){/* 1.回合第一步, 服务器接收 */	info st;ret = recv(clifd, &st,sizeof(info),0); /* recv 接收出错会返回 -1 */	/* 2.服务器解析 客户 数据包 */	if(st.cmd == CMD_REGISTER){printf("用户要注册学生信息 \n");printf("学生姓名:%s, 学生年龄: %d \n",st.name, st.age);/* 3.回合第三步, 回复客户端  */st.stat = STAT_OK;ret = send(clifd, &st,sizeof(info),0); /* recv 接收出错会返回 -1 */	}if(st.cmd == CMD_CHECK){}}return 0;
}/*************************************************************
3.9.4.5、表示IP地址相关数据结构
(1)都定义在 netinet/in.h
(2)struct sockaddr,这个结构体是网络编程接口中用来表示一个IP地址的,注意这个IP地址是不区分IPv4和IPv6的(或者说是兼容IPv4和IPv6的)
(3)typedef uint32_t in_addr_t;		网络内部用来表示IP地址的类型
(4)struct in_addr{in_addr_t s_addr;};
(5)struct sockaddr_in{__SOCKADDR_COMMON (sin_);    宏定义 :这个是看 是IPV4 还是 IPV6  in_port_t sin_port;                   端口号struct in_addr sin_addr;          	IP地址unsigned char sin_zero[sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)];};
(6)struct sockaddr			这个结构体是linux的网络编程接口中用来表示IP地址的标准结构体,bind、connect等函数中都需要这个结构体,这个结构体是兼容IPV4和IPV6的。在实际编程中这个结构体会被一个struct sockaddr_in或者一个struct sockaddr_in6所填充。const struct sockaddr *address 就等同于  struct sockaddr_in*******************************************************************/

客户端程序 client.c

#include <stdio.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>/* 客户端端口 号 可以自己分配的,只有 和 服务器的 端口号 一直才能连接上 服务器 */#define SERADDR  "192.168.80.128 " /* 服务器给我们 开放的 IP 地址 和 端口号 */
#define SERPORT  6003
#define BACKLOG 10char sendbuf[100]={0};
char recvbuf[100];#define CMD_REGISTER  1001 /*注册学生信息 */
#define CMD_CHECK     1002  /*检查 学生信息 */
#define CMD_GETINFO   1003  /*获取 学生信息 */#define STAT_OK    30
#define STAT_ERR   31typedef struct commu
{char name[20]; /* 学生姓名 */int age;  /* 学生年龄 */int cmd; /*命令码*/int stat; /*状态信息, */}info;int main(void)
{int sockfd = -1;  /* 定义一个接收 socket 文件描述符(socket 的返回值) */int ret = -1;/* 定义一个接收 bind (bind 的返回值) */struct sockaddr_in seraddr = {0}; /* 定义一个connect 第二个参数(输入型参数) 这个结构体是网络编程接口中用来表示一个IP地址的 *//* 1 . 先 socket  打开文件描述符 */sockfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == sockfd){perror("socket");return -1;}printf("sockfd = %d \n", sockfd);/* 2. connect  */seraddr.sin_family = AF_INET;  /* 设置 地址族为 IPV4 */seraddr.sin_port = htons(SERPORT);           /* 服务器端口号  htons 当前电脑 字节序 转成 网络 字节序 16位 */seraddr.sin_addr.s_addr = inet_addr(SERADDR);   /* 设置 IP地址 */ret = connect(sockfd,(const struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){perror("connect");return -1;}printf("成功建立连接 \n");/*  建立连接后 就可以通讯了 */	
#if 0	strcpy(sendbuf,"hello world");ret = send(sockfd,sendbuf,strlen(sendbuf), 0);printf("发送了 %d 个字符 \n",ret);
#endifwhile(1){/*  1. 客户端 首先给服务器 发送数据包 */	info st1;printf("请输入学生姓名\n");scanf("%s",st1.name);printf("请输入学生年龄\n");scanf("%d",&st1.age);st1.cmd = CMD_REGISTER;//printf("刚才输入的是 %s \n",sendbuf);ret = send(sockfd,&st1,sizeof(info), 0);printf("发送了多少个字节 %d \n",ret);/* 2.回合第2步,客户端 接收 服务器的回复  */memset(&st1,0,sizeof(info));	ret = recv(sockfd, &st1,sizeof(info),0); /* recv 接收出错会返回 -1 */	/* 3.回合第3步,客户端 解析 服务器的回复,在做下一步定夺  */if(st1.stat == STAT_OK){printf("注册学生信息成功 \n");printf(" \n");}else{printf("注册学生信息失败 \n");}}return 0;
}

运行结果:


3.9.9.3、常用应用层协议:http、ftp······
3.9.9.4、UDP简介

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/28188.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu学习笔记(二)——文件属性与权限

文章目录 前言一、用户与用户组1.用户&#xff08;文件拥有者&#xff09;2.用户组3.其他人 二、Linux用户身份与用户组记录文件1. /etc/passwd2. /etc/shadow3. /etc/group 三、文件属性与权限1. 查看文件属性的方法&#xff08;ls&#xff09;2.文件属性详细介绍2.1 权限2.2 …

jib进行本地打包,并上传本地镜像仓库

使用 Jib 进行本地打包和上传到本地镜像仓库是一种方便的方式&#xff0c;而无需编写 Dockerfile。Jib 是一个开源的 Java 容器镜像构建工具&#xff0c;它可以直接将 Java 项目打包为镜像&#xff0c;并将其推送到容器镜像仓库。 gradle 进行jib的配置 import java.time.Zon…

msvcp140.dll丢失怎么弄?分享几个最靠谱的解决方法

当你在运行某个程序或游戏时&#xff0c;突然收到一个错误提示&#xff0c;提示你的计算机缺少msvcp140.dll文件。这意味着你的计算机中缺少一个重要的系统文件&#xff0c;可能会导致程序无法正常运行。下面是一些详细的解决方法&#xff0c;帮助你解决msvcp140.dll丢失的问题…

Windows与Linux取证分析

目录 一、电子数据取证基本概念 1.电子取证学 2.常规取证 3.洛卡德物质交换原理 4.电子数据范围 5.电子数据取证的概念和目的 6.电子数据取证过程 二、Linux系统取证 1.基本信息获取 &#xff08;1&#xff09;获取系统基础信息 &#xff08;2&#xff09;用户/用户…

Windows安装Oh-My-Posh美化Powershell

Windows Terminal&#xff1a;https://www.microsoft.com/store/productId/9N0DX20HK701 最新Powershell下载&#xff1a;https://github.com/PowerShell/PowerShell/releases Oh-My-Posh官网&#xff1a;https://ohmyposh.dev/ Nerd字体下载&#xff1a;https://www.nerdfonts…

ubuntu20.04配置vscode

下载&#xff1a; https://az764295.vo.msecnd.net/stable/660393deaaa6d1996740ff4880f1bad43768c814/code_1.80.0-1688479026_amd64.debhttps://az764295.vo.msecnd.net/stable/660393deaaa6d1996740ff4880f1bad43768c814/code_1.80.0-1688479026_amd64.deb 安装&#xff1a…

Mysql数据库之事务

目录 一、事务的概念 二、事务的ACID特点 1.原子性&#xff08;Atomicity&#xff09; 2.一致性&#xff08;Consistency&#xff09; 3.隔离性&#xff08;lsolation&#xff09; 4.持久性&#xff08;Durability) 三、并发访问表的一致性问题和事务的隔离级别 1.并发访…

【C++】开源:跨平台轻量日志库easyloggingpp

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍跨平台轻量日志库easyloggingpp。 无专精则不能成&#xff0c;无涉猎则不能通。。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&am…

春秋云境—Initial

文章目录 春秋云境—Initial一、前期准备1、靶标介绍2、相关设备 二、WEB渗透1、ThinkPHP RCE&#xff08;1&#xff09;、打开网站&#xff08;2&#xff09;、检测漏洞 2、蚁剑连接3、sudo提权4、frpc代理5、fsacn扫描 三、后渗透1、信呼OA RCE&#xff08;1&#xff09;、1.…

Typora设置Gitee图床,自动上传图片

之前写了一篇同类型文章&#xff1a;如何将Typora中图片上传到csdn 实现了Typora本地编辑的内容中的图片&#xff0c;可以直接复制到csdn上进行发布。但是在使用过程中发现sm.ms这个图床站不是很稳定&#xff0c;即使用了翻墙也不稳定。 这篇文章推荐使用Gitee作为图床&#xf…

001-Spring简要原理分析-草稿

Bean查找流程 根据类型找找到多个根据名称找 Map<被代理类&#xff0c; List<方法>> 事务 Config 方法代理

还在使用冒泡排序遍历数组?No No No 库函数qsort帮你搞定所有排序还不快学起来!

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《快速入门C语言》《C语言初阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言&#x1f4ac; 库函数qsort的介绍&#x1f4ac; 库函数qsort的参数介绍&#x1f4ad; 参数一 (void* base)…