UC编程之网络通信(TCP/UDP)
2024-11-10 12:57:43
原文网络常识
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端: ...
随机推荐
- 用dedecms自定义表单创建简易自助预约系统
建站往往需要根据客户的需求来增加相应的功能,比如预约.平时用比较多的是织梦系统,那么如何用dedecms自定义表单创建简易自助预约系统呢? 进入dedecms后台,左侧菜单中依次点击“核心” - 频道 ...
- BZOJ2435: [Noi2011]道路修建
这种水题真是……没一次AC都不好意思见人啊 P.S. LINUX无限栈真是爽炸了… 我爱递归 /**************************************************** ...
- C#中“貌似”跳出while(true)死循环
当程序第一次执行到Read()函数时,程序会被阻塞,然后输入字符,Enter之后程序被激活,windows平台会自动在输入字符之后加入回车符和换行符,此时输入流中就有三个字符,然而read每次只读取一 ...
- 历代诗词咏宁夏注释1----常星景:< 六盘>
六盘 常星景 关中形势甲天下,四岳分峙西太华.[1] 中有汭泾经纬之,六盘嵚崎历历落.[2] □□□□其流亚,终年峰头雪不消. 弟畜太白兒美高,眼底培缕纷纷何足数,呼吸想通天尺五.[3] 西北堆镇一切 ...
- Apache POI 解析 microsoft word 图片文字都不放过
http://blog.csdn.net/njchenyi/article/details/6894500 http://haohaoxuexi.iteye.com/blog/2031335
- Spring mvc json null
http://blog.csdn.net/zdsdiablo/article/details/9429263
- CF 197 DIV2 Xenia and Bit Operations 线段树
线段树!!1A 代码如下: #include<iostream> #include<cstdio> #define lson i<<1 #define rson i ...
- Linux网络编程6——使用TCP实现文件服务器
需求 当客户端连接上服务器后,服务器会将相应文件传输给客户端,实现文件下载. 思路 服务器端,主进程负责listen.循环内,主进程每从任务请求队列中accept出一个请求,就fork出孙子完成文件传 ...
- UVA 10497 - Sweet Child Makes Trouble 高精度DP
Children are always sweet but they can sometimes make you feel bitter. In this problem, you will see ...
- Protobuf动态解析那些事儿
需求背景 在接收到 protobuf 数据之后,如何自动创建具体的 Protobuf Message 对象,再做反序列化.“自动”的意思主要有两个方面:(1)当程序中新增一个 protobuf Mes ...