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端: ...
随机推荐
- 编译libcore-amr静态库
在此链接下 https://github.com/feuvan/opencore-amr-iOS 下载它的源码到本地, 然后cd到此目录下,在终端输入命令./build_ios_xcode6.sh,便 ...
- 亚马逊 在线测试题目 amazon
分析:其实就是求矩形中某一个点到其他点的距离加权最小 方法一: 对每一个点求其到其他点的加权距离,然后比较最小.由于有M*N个点,对每一个点求加权距离是O(M*N)的,所以整体时间复杂度是O(M*M* ...
- 在centos 6.5 在virtual box 上 安装增强版工具
centos 6.5 在virtual box 上 安装增强版工具: 出现:centos unable to find the source of your current linux kernel ...
- ObjectStore onFetch方法获取记录总数
转自:http://blog.csdn.net/earthhour/article/details/38686029 ObjectStore onFetch方法获取记录总数 require(['doj ...
- C++时间标准库时间time和系统时间的使用
#include <iostream> #include <time.h> #include <stdio.h> #include <windows.h> ...
- self._raiseerror(v) File "D:\GameDevelopment\Python27\lib\xml\etree\ElementTree.py", line 1506, in _raiseerror
D:\BaiDuYun\Plist>python unpack_plist.py lobbyRelieveTraceback (most recent call last): File &quo ...
- Sqli-labs less 19
Less-19 从源代码中我们可以看到我们获取到的是HTTP_REFERER 那和less18是基本一致的,我们从referer进行修改. 还是像less18一样,我们只给出一个示例 将referer ...
- PHP-Java-Bridge使用笔记,2014年9月最新版
这是我在做平安银行开发的时候,本地使用PHP环境,平安银行接口为Java接口的时候,采用PHP-Java-Bridge的方式调用接口的笔记.因为现在网上的教程基本上都不行了,所以在这里贴出我能使用的而 ...
- Python - 装饰器使用过程中的误区
曾灵敏 - APRIL 27, 2015 装饰器基本概念 大家都知道装饰器是一个很著名的设计模式,经常被用于AOP(面向切面编程)的场景,较为经典的有插入日志,性能测试,事务处理,Web权限校验, C ...
- C#&java重学笔记(泛型)
C#部分: 1.泛型的出现主要用于解决类.接口.委托.方法的通用性,通过定义泛型类.接口.委托.方法,可以让不同类型的数据使用相同运算规则处理数据,方便了开发. 2.利用System.Nullable ...