UC编程之网络通信(TCP/UDP)
2024-08-18 02:37:32
原文网络常识
OSI 7层模型(人机交互)
物理层、数据链路层、网络层、传输层、会话层、表现层、应用层
常见协议:
tcp/udp/ip/ftp/http...
IP地址--就是计算机在网络中的地址,是一个32位的整数(IPV4),目前也有IPV6
IP地址在计算机中,以一个整数格式保存。因此IP地址在底层的描写方式:8位16进制。点分10进制是人类描述IP地址的主要方式。每个字节计算一个10进制的整数,中间用 “.”隔开。
192.168.0.20(点分十进制0-255)
==0xC0 A8 00 14(8位16进制)
IP地址分为A B C D 4类。
子网掩码--判断计算机是不是在一个局域网上
166.111.160.1与166.111.161.45
子网掩码:255.255.254.0
166.111.160.1
255.255.254.0 (位与)
--------------
166.111.160.0
166.111.161.45
255.255.254.0 (位与)
--------------
166.111.160.0
结论:166.111.160.1与166.111.161.45在同一个局域网
IP地址只能定位计算机,但没有访问权限。
端口会开放访问的权限。端口可以用来定位计算机中的某个进程。
网络编程必须提供IP地址和端口号。
端口号是unsigned short,范围:0-65535
0-1023 固有端口(不推荐使用)计算机预留
1024-48XX 程序员使用的端口 安装某些程序也会占用,但很少
48XX - 65535 不建议用,不稳定
MAC地址,物理地址,是网卡的物理地址。IP地址和MAC地址绑定在一起。
字节次序--计算机在存储整数时,有从高到低 和 从低到高之分,叫字节次序。字节次序在计算机中不确定,在网络传输的过程中是固定的。
因此,对于端口,需要本地格式和网络格式之间的转换。
域名:俗称网址,就是IP地址的助记,通过域名解析服务器 网址解析成IP地址完成访问。
网络编程--Windows/Unix 都支持
socket编程
socket--插座、套接字(IP + 端口)
关于socket编程的一些函数和常识
socket编程分为:一对一 和 一对多
一对一:
socket通信包括本地通信(ipc)和网络通信
一对一通信模型:
服务器端编程步骤:
1 创建一个socket,使用socket()
int socket(int domain,int type,int protocol)
domain--域,用来选择协议
PF_UNIX PF_LOCAL PF_FILE 本地通信
PF_INET 网络通信
PF_INET6 网络通信(IPV6)
注:PF也可以换成AF
type--用来选择通信类型
SOCK_STREAM --数据流,针对TCP协议
SOCK_DGRAM --数据报,针对UDP协议
protocol--本来应该用来指定协议,但没用了,因为协议已经被前2个参数指定,给 0即可
返回socket描述符,失败返回-1
2 准备通信地址
关于通信地址有3个结构体:
struct sockaddr{
int sa_family;//协议
char sa_data[];//地址
}
这个结构sockaddr不被真正使用,只是用来做相关函数的参数(不存数据)。
本地通信使用结构体:
#include<sys/un.h>
struct sockaddr_un{
int sun_family;//协议
char sun_path[];//socket文件的路径
}
网络通信使用结构体:
#include<netinet/in.h>
struct sockaddr_in{
int sin_family;//协议
short port;//端口号
struct in_addr sin_addr;//IP地址
}
3 绑定函数bind()
bind(int sockfd,sockaddr,length)
4 通信(read/write)
5 关闭 close(sockfd)
客户端编程步骤:
与服务器端基本一样,除了第三步,第三步使用connect(),参数与bind一样
注:服务器和客户端数据交互时,读写必须必须保持一致性(一边读,另一方写)
查看本机IP地址的命令:
Windows --ipconfig
Unix -- ifconfig
whereis 可以查看命令所在的目录
ping IP地址 可以检测网络是否畅通
本地通信实例:
服务器端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5 #include<sys/socket.h>
6 #include<sys/un.h>
7
8 int main(){
9 int sockfd = socket(PF_UNIX,SOCK_DGRAM,0);
10 if(sockfd == -1) perror("socket"),exit(-1);
11 struct sockaddr_un addr;
12 addr.sun_family = PF_UNIX;//与socket第一个参数保持一致
13 strcpy(addr.sun_path,"a.sock");
14 int res = bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
15 if(res == -1) perror("bind"),exit(-1);
16 printf("bind ok!\n");
17 char buf[100]={};
18 res = read(sockfd,buf,sizeof(buf));
19 printf("读了%d字节k,内容%s\n",res,buf);
20 close(sockfd);
21 return 0;
22 }
客户端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5 #include<sys/socket.h>
6 #include<sys/un.h>
7
8 int main(){
9 int sockfd = socket(PF_UNIX,SOCK_DGRAM,0);
10 if(sockfd == -1) perror("socket"),exit(-1);
11 struct sockaddr_un addr;
12 addr.sun_family = PF_UNIX;
13 strcpy(addr.sun_path,"a.sock");
14 int res = connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
15 if(res == -1) perror("connect"),exit(-1);
16 printf("connect ok!\n");
17 write(sockfd,"hello",5);
18 close(sockfd);
19 return 0;
20 }
网络通信:
服务器端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5 #include<sys/socket.h>
6 #include<netinet/in.h>
7
8 int main(){
9 int sockfd = socket(PF_INET,SOCK_DGRAM,0);
10 if(sockfd == -1) perror("socket"),exit(-1);
11 struct sockaddr_in addr;
12 addr.sin_family = PF_INET;
13 addr.sin_port =htons(2222);//端口
14 addr.sin_addr.s_addr =inet_addr("192.168.13.73");//服务器ip地址
//inet_addr将点分十进制转换成整数ip
15 int res = bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
16 if(res == -1) perror("bind"),exit(-1);
17 char buf[100]={};
18 res =read(sockfd,buf,100);
19 printf("读到了res=%d字节,内容是%s\n",res,buf);
20 return 0;
21 }
客户端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5 #include<sys/socket.h>
6 #include<netinet/in.h>
7
8 int main(){
9 int sockfd = socket(PF_INET,SOCK_DGRAM,0);
10 if(sockfd == -1) perror("socket"),exit(-1);
11 struct sockaddr_in addr;
12 addr.sin_family = PF_INET;
13 addr.sin_port =htons(2222);
14 addr.sin_addr.s_addr =inet_addr("192.168.13.73");/服务器ip地址
//inet_addr将点分十进制转换成整数ip
//服务器端和客户端的ip都是服务器ip地址
15 int res = connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
16 if(res == -1) perror("bind"),exit(-1);
17 write(sockfd,"hello",5);
18 return 0;
19 }
TCP 一对多编程步骤:
服务器端:
1 调用socke()创建socket,type必须是SOCK_STREAM(保证使用TCP模式)
2 准备通信地址sockaddr_in
3 bind()绑定
4 监听 listen(),为accept()做准备
5 等待客户端的连接accept()
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
参数sockfd就是第一步的socket
参数addr就是链接上来的客户端的通信地址
参数len是一个传入传出参数,传入通信地址的大小,传出客户端通信地址 的大小
(要准备一个sockaddr_in 结构来存放客户端通信地址)
返回新的socket描述符,用来和客户端进行通信
6 读写数据 read/write
7 关闭socket
注:第一步的socket主要用于等待连接,不参与信息交互。第五步的socket主要用于和客户端之间的通信
客户端:
1 调用socke()创建socket,type必须是SOCK_STREAM(保证使用TCP模式)
2 准备通信地址sockaddr_in
3 connect()绑定
4 通信(read/write)
5 关闭 close(sockfd)
TCP---一对多实例:
服务器端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/socket.h>
5 #include<netinet/in.h>
6 #include<arpa/inet.h>
7 #include<signal.h>
8 int sockfd;
9 void fa(){
10 close(sockfd);
11 printf("服务器关闭\n");
12 exit(0);
13 }
14 int main(){
15 signal(SIGINT,fa);//ctrl+c 信号关闭服务器
16 sockfd = socket(PF_INET,SOCK_STREAM,0);//创建
17 if(sockfd == -1) perror("socket"),exit(-1);
18 struct sockaddr_in addr;
19 addr.sin_family = PF_INET;
20 addr.sin_port = htons(2222);//端口
21 addr.sin_addr.s_addr = inet_addr("192.168.13.85");//服务器ip
22 //解决重启时地址被占用问题
23 int reuseaddr = 1;
24 setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,
&reuseaddr,sizeof(reuseaddr) );
25 int res = bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
//绑定,激活端口
26 if(res == -1) perror("bind"),exit(-1);
27 printf("bind ok\n");
28 listen(sockfd,100);//监听
29 while(1){
30 struct sockaddr_in from;//存放连接的客户端信息
31 socklen_t len = sizeof(from);
32 int fd = accept(sockfd,(struct sockaddr*)&from,&len);
//等待客户端连接
33 char* fromip = inet_ntoa(from.sin_addr);
34 printf("客户端%s连接成功\n",fromip);
35 pid_t pid = fork();//创建子进程(目前还为学习线程)
36 if(pid == 0){
37 while(1){
38 char buf[100] = {};
39 read(fd,buf,100);
40 printf("buf=%s\n",buf);
41 if(strcmp(buf,"byp")==0) break;
42 write(fd,buf,strlen(buf));
43 }
44 close(fd);
45 exit(0);
46 }
47 close(fd);
48 }
客户端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/socket.h>
5 #include<netinet/in.h>
6 #include<arpa/inet.h>
7
8 int main(){
9 int sockfd = socket(PF_INET,SOCK_STREAM,0);
10 if(sockfd == -1) perror("socket"),exit(-1);
11 struct sockaddr_in addr;
12 addr.sin_family = PF_INET;
13 addr.sin_port = htons(2222);//端口
14 addr.sin_addr.s_addr = inet_addr("192.168.13.85");//服务器ip
15 int res = connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));//连接
16 if(res == -1) perror("bind"),exit(-1);
17 printf("connect ok\n");
18 while(1){
19 char word[100] ={};
20 printf("请输入要说的话\n");
21 scanf("%s",word);
22 write(sockfd,word,strlen(word));
23 if(strcmp(word,"bye")==0) break;
24 char buf[100] = {};
25 read(sockfd,buf,100);
26 printf("buf=%s\n",buf);
27 }
28 close(sockfd);
29 return 0;
30 }
基于TCP协议的服务器和客户端直接的通信除了用read()/write()还可以用
recv()/send()
UDP --用户数据报协议
关于TCP和UDP的区别:
TCP -- 有连接协议,在通信的全程保持连接
TCP优点:重发一切错误数据,保证数据的正确和完整,缺点:服务器端压力
非常大,资源占用率比较高。
UDP -- 无连接协议,在发送数据的时候连接一下,不保持任何的连接
UDP优点:效率高,资源占用少。缺点:不保证数据的完整和正确。
UDP网络编程的函数 --发送数据和接受数据
sendto() 和 recvfrom()
几点注意:
1 第二步准备通信地址,都是服务器端的通信地址
2 客户端的通信地址,TCP用accept()函数拿,UDP用recvfrom拿(发送端口)。
客户端的端口是自动分配的。
3 TCP的信息交互函数:read/write/send/recv
UDP的信息交互函数:read/write/send/recv,但上面的函数不能取得发送方通信地址,因此更多时候,使用sendto/recvfrom
4 网络信息接收函数 一般会阻塞代码
5 服务器端都必须使用bind(),bind()函数的作用就是服务器端开发一个端口(把端口和进程绑定起来)。而客户端自动完成的。
UDP实例:
服务器端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/socket.h>
4 #include<netinet/in.h>
5 #include<arpa/inet.h>
6 #include<string.h>
7
8 int main(){
9 int sockfd =socket(PF_INET,SOCK_DGRAM,0);//创建
10 if(sockfd == -1) perror("socket"),exit(-1);
11 struct sockaddr_in addr;
12 addr.sin_family = PF_INET;
13 addr.sin_port = htons(2222);//端口
14 addr.sin_addr.s_addr = INADDR_ANY;//本机IP
15 int res = bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));//开放端口
16 if(res == -1) perror("bind"),exit(-1);
17 printf("bind ok\n");
18 char buf[100] ={};
19 struct sockaddr_in from;//用于保存客户端信息,以便回发信息
20 socklen_t len = sizeof(from);
21 recvfrom(sockfd,buf,100,0,(struct sockaddr*)&from,&len);//接收信息
22 //read(sockfd,buf,100);
23 printf("buf=%s\n",buf);
24 sendto(sockfd,"welcome",7,0,(struct sockaddr*)&from,len);//发送信息
25 close(sockfd);
26 return 0;
27 }
客户端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/socket.h>
4 #include<netinet/in.h>
5 #include<arpa/inet.h>
6 #include<string.h>
7
8 int main(){
9 int sockfd = socket(PF_INET,SOCK_DGRAM,0);
10 if(sockfd == -1) perror("socket"),exit(-1);
11 struct sockaddr_in addr;
12 addr.sin_family = PF_INET;
13 addr.sin_port = htons(2222);
14 addr.sin_addr.s_addr = INADDR_ANY;
15 // write(sockfd,"hello",5);没有接收方地址
16 sendto(sockfd,"hello",5,0,(struct sockaddr*)&addr,sizeof(addr));
17 char buf[100] ={};
18 // read(sockfd,buf,100);
19 struct sockaddr_in from;
20 socklen_t len =sizeof(from);
21 recvfrom(sockfd,buf,100,0,(struct sockaddr*)&from,&len);
22 char* fromip = inet_ntoa(from.sin_addr);
23 printf("%s发来%d字节信息\n",fromip,len);
24 printf("%s\n",buf);
25 close(sockfd);
26 return 0;
27 }
时间服务器:
服务端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/socket.h>
4 #include<netinet/in.h>
5 #include<arpa/inet.h>
6 #include<string.h>
7 #include<signal.h>
8 #include<time.h>
9
10 int sockfd;
11 void fa(int signo){
12 close(sockfd);
13 printf("关闭服务器成功!\n");
14 exit(-1);
15 }
16 int main(){
17 signal(SIGINT,fa);
18 int sockfd =socket(PF_INET,SOCK_DGRAM,0);
19 if(sockfd == -1) perror("socket"),exit(-1);
20 struct sockaddr_in addr;
21 addr.sin_family = PF_INET;
22 addr.sin_port = htons(2222);//端口
23 addr.sin_addr.s_addr = INADDR_ANY;//服务器IP
24 int res = bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));//开放端口
25 if(res == -1) perror("bind"),exit(-1);
26 printf("bind ok\n");
27 while(1){
28 char buf[100] ={};
29 struct sockaddr_in from;
30 socklen_t len = sizeof(from);
31 recvfrom(sockfd,buf,100,0,(struct sockaddr*)&from,&len);
32 if(strcmp(buf,"hello")==0){
33 char ts[100]={};
34 time_t curtime = time(0);//获得当前时间秒数
35 struct tm* cur = localtime(&curtime);//将时间秒数转换成tm结构
36 sprintf(ts,"%4d-%02d-%02d %02d:%02d:%02d",
cur->tm_year+1900,cur->tm_mon+1,cur->tm_mday,
cur->tm_hour,cur->tm_min,cur->tm_sec) ;
38 sendto(sockfd,ts,strlen(ts),0,(struct sockaddr*)&from,len);//发送
39 }
40 }
41 return 0;
42 }
客户端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/socket.h>
4 #include<netinet/in.h>
5 #include<arpa/inet.h>
6 #include<string.h>
7
8 int main(){
9 int sockfd = socket(PF_INET,SOCK_DGRAM,0);
10 if(sockfd == -1) perror("socket"),exit(-1);
11 struct sockaddr_in addr;
12 addr.sin_family = PF_INET;
13 addr.sin_port = htons(2222);
14 addr.sin_addr.s_addr = INADDR_ANY;
15 // write(sockfd,"hello",5);没有接收方地址
16 sendto(sockfd,"hello",5,0,(struct sockaddr*)&addr,sizeof(addr));
17 char buf[100] ={};
18 // read(sockfd,buf,100);
19 struct sockaddr_in from;
20 socklen_t len =sizeof(from);
21 recvfrom(sockfd,buf,100,0,(struct sockaddr*)&from,&len);
22 char* fromip = inet_ntoa(from.sin_addr);
23 printf("%s发来%d字节信息\n",fromip,len);
24 printf("%s\n",buf);
25 close(sockfd);
26 return 0;
27 }
UC编程之网络通信(TCP/UDP)的更多相关文章
- 【深入浅出Linux网络编程】 “实践 -- TCP & UDP”
通过上一篇博客的学习,你应该对基于epoll的事件触发机制有所掌握,并且通过阅读sio.c/sio.h应该也学会了如何封装epoll以及如何通过设计令epoll更加实用(用户回调,用户参数). 简单回 ...
- 三十天学不会TCP,UDP/IP编程--MAC地址和数据链路层
这篇文章主要是来做(da)推(guang)介(gao)的!由于这两年接触到了比较多的这方面的知识,不想忘了,我决定把他们记录下来,所以决定在GitBook用半年时间上面写下来,这是目前写的一节,后面会 ...
- 三十天学不会TCP,UDP/IP网络编程-IP头格式祥述
我又来了,这篇文章还是来做(da)推(guang)介(gao)我自己的!俗话说事不过三,我觉得我下次得换个说法了,不然估计要被厌恶了,但是我是好心呐,一定要相信我纯洁的眼神.由于这两年接触到了比较多的 ...
- Python的网络编程[0] -> socket[0] -> socket 与 TCP / UDP
Socket socket 简述 / socket Abstract 网络进程通信与 socket 网络中进程之间如何通信,首要解决的问题是如何唯一标识一个进程,否则通信无从谈起.在本地可以通过进程 ...
- 开源基于asio的网络通信框架asio2,支持TCP,UDP,HTTP,RPC,SSL,跨平台,支持可靠UDP,支持TCP自动拆包,TCP数据报模式等
开源基于asio的网络通信框架asio2,支持TCP,UDP,HTTP,RPC,SSL,跨平台,支持可靠UDP,支持TCP自动拆包,TCP数据报模式等 C++开发网络通信程序时用asio是个不错的选择 ...
- TCP/UDP Linux网络编程详解
本文主要记录TCP/UDP网络编程的基础知识,采用TCP/UDP实现宿主机和目标机之间的网络通信. 内容目录 1. 目标2.Linux网络编程基础2.1 嵌套字2.2 端口2.3 网络地址2.3.1 ...
- 网游中的网络编程系列1:UDP vs. TCP
原文:UDP vs. TCP,作者是Glenn Fiedler,专注于游戏网络编程相关工作多年. 目录 网游中的网络编程系列1:UDP vs. TCP 网游中的网络编程2:发送和接收数据包 网游中的网 ...
- Java 网络编程(二) 两类传输协议:TCP UDP
链接地址:http://www.cnblogs.com/mengdd/archive/2013/03/09/2951841.html 两类传输协议:TCP,UDP TCP TCP是Transfer C ...
- Windows下C语言的Socket编程例子(TCP和UDP)
原文:Windows下C语言的Socket编程例子(TCP和UDP) 刚刚学windows编程,所以想写学习笔记,这是一个简单的Socket程序例子,开发环境是vc6: 首先是TCP server端: ...
随机推荐
- 一个包的libevent流程
//一个发包的流程 第一个包就是客户端的心跳包,现在加了版本的包 再来看看这个发包打包过程,过程坚持,但理解费劲 void NGP::OnliveTimer()//客户端心跳,5s发一次 { Send ...
- Sqli-labs less 58
Less-58 执行sql语句后,并没有返回数据库当中的数据,所以我们这里不能使用union联合注入,这里使用报错注入. Payload:http://127.0.0.1/sqli-labs/Less ...
- POJ 2513 Colored Sticks (离散化+并查集+欧拉通路)
下面两个写得很清楚了,就不在赘述. http://blog.sina.com.cn/s/blog_5cd4cccf0100apd1.htmlhttp://www.cnblogs.com/lyy2890 ...
- 强大的grep命令
1.作用 Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全 ...
- NDK 编译可执行程序
以Hello Android工程为例. 建立好工程hello-a,在jni目录下创建文件hello-a.c,文件内容如下.(注意是jni目录,使用src目录编译会出错) #include <st ...
- 饶有兴致的用javascript做了个贪食蛇游戏
09年写的东西.一直藏在自己的记事本里头,现在开始整理写博客,所以直接搬过来 先上效果图 再添代码: <HTML> <HEAD> <TITLE>贪吃蛇 Snake ...
- C# 设置程序开机自动运行(+注册表项)
有时候我们需要让软件安装好了,开机自动运行,这时我们需要把启动项加载到注册表中,需要注意的时现在很多杀毒软件在其他软件更改注册表的时候会有提示,可能会阻止.下面代码包含增加启动项到注册表和删除启动项. ...
- Xamarin for Visual Studio 破解日志
一.相关声明 本文涉及的 Xamarin 系列软件的版权为 Xamarin Inc. 所有 以本文涉及的思路和方法破解的软件,禁止用于商业用途 如无必要,学习和研究时最好以正版为准 团队或土豪等若觉得 ...
- Java常用类库
System System:类中的方法和属性都是静态的. out:标准输出,默认是控制台. in:标准输入,默认是键盘. System描述系统一些信息.获取系统属性信息:Properties getP ...
- Linux 删除文件夹和文件的命令
linux删除目录很简单,很多人还是习惯用rmdir,不过一旦目录非空,就陷入深深的苦恼之中,现在使用rm -rf命令即可.直接rm就可以了,不过要加两个参数-rf 即:rm -rf 目录名字-r 就 ...