网络编程
来源:互联网 发布:淘宝女装货源 编辑:程序博客网 时间:2024/05/17 07:48
在一次服务中提供数据或服务的称为服务器,获取数据的称为客户端。
在网络基础中讲到有许多协议,那这里就面临协议的选择,TCP还是UDP?
先来看看TCP和UDP的区别:
TCP:
面向连接的(服务器和客户端之间维护一条专有线路)
可靠的(数据无差错、不丢失、不重复、并且按序到达)
流式服务
UDP:
无连接(每次都要探寻线路)
不可靠的
数据报服务
线路连接上以后,未来时间段不间断发送数据,选择TCP。但是维护连接线路要付出代价,根据数据是否重要来选择可靠还是不可靠,有些数据不一定要求可靠。
两种协议自然就有两种编程方式:
TCP编程流程:
- 服务器端sever:
- 创建socket
- bind(将IP地址和端口号命名,一般我们访问网站都不是直接输IP地址的吧)
- listen(监听连接,创建监听队列)
- accept(从listen拿到已经完成连接的)
- recv/send(收发数据)
- close(关闭连接,所有完成后再关闭一次socket)
- 客户端client:
- 创建socket ()/* bind 一般不要*/
- 发起连接connect
- recv/send(收发数据)
- close
具体函数如下:
1、创建socket
int socket(int domain, int type, int protocol); //domain 协议簇 IPv4(AF_INET)/ IPv6(AF_INET6); //type 选择TCP(SOCK_STREAM)还是UDP(SOCK_DGRAM); //protocol TCP下具体的哪个协议,现在已经不用,给0; //成功返回一个socket文件描述符,失败返回-1;
2、命名socket
int bind(int sockfd,const struct sockaddr*addr,int addrlen);//sockfd socket函数返回的文件描述符;//addr 指定IP地址和端口号//addrlen 该socket地址的长度//成功返回0,失败返回-1并设置erron。常见erron是EACCESS(被绑定的地址是受保护的地址,即小于1024,仅超级用户能够访问)EADDRINUSE(被绑定的地址正在使用中)
struct sockaddr_in{ sa_family_t sin_family; /*地址族:AF_INET*/ u_int16_t sin_port; /*端口号(网络字节序:大端模式)*/ struct in_addr sin_addr; /*IPv4地址结构体*/};struct sin_addr{ u_int32_t s_addr; /*IPv4地址,用网络字节序表示*/};
所有专用socket地址类型的变量在实际使用时都需要强制转换成通用的sockaddr地址类型,因为所有socket编程接口使用的地址参数类型都是sockaddr。当然在这里也要弄清楚主机字节序和网络字节序。
通常都是用点分十进制字符串表示IPv4地址,但是编程中需要转换成整数(二进制)使用。系统提供了3个函数用于,点分十进制字符串表示的IPv4地址和用网络字节序整数表示的IPv4地址之间的转换:
#include<arpa/inet.h>int_addr_t inet_addr(const char*str);//将点分十进制字符串表示的IPv4地址转换成用网络字节序整数表示的IPv4地址,失败时返回INADDR_NONE,方便
int inet_aton(const char*cp,struct in_addr *inp);//将点分十进制字符串表示的IPv4地址转换成用网络字节序整数表示的IPv4地址,将转化结果储存于参数inp指向的地址结构中,成功返回1,失败返回0.相比于inet_addr更安全char *inet_ntoa(struct in_addr in);//将用网络字节序整数表示的IPv4地址转换成点分十进制字符串表示的IPv4地址,该函数不可重入3、监听socket
int listen(int sockfd, int backlog);//创建一个监听队列,有连接放到队列中,backlog表示队列大小,但是底层有默认值,给的小了就用默认值//成功返回0,失败返回-1
4、接收连接
int accept(int sockfd,struct sockaddr*addr,int len);//sockfd 执行过listen监听的socket//addr 记录客户端的IP地址和端口号//len 长度//成功返回获取到的和客户端连接的文件描述符,此后由该返回值和客户端通信,失败返回-1
5、发起连接
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);//addr 要连接的服务器的IP地址和端口号//成功返回0,失败返回-16、关闭连接
int close(int fd);//fd 待关闭的socket
7、收发数据
#include<sys/typs.h>#include<sys/socket.h>ssize_t recv(int sockfd, void*buf, size_t len, int flags);//接受(读取)sockfd上的数据,放到buf缓冲区,大小为len,flags暂且设为0;//成功返回实际读取到的数据长度,返回0说明对方已关闭连接,出错返回-1;ssize_t send(int sockfd, const void*buf, size_t len, int flags);//buf缓冲区的数据发送(写入)sockfd,大小为len,flags暂且设为0;//成功返回实际读写入数据长度,出错返回-1;
既然要完成通信,那么至少有一个服务器端一个客户端,代码如下:
//服务器端ser.c void main(){ int sockfd = socket(AF_INET,SOCK_STREAM,0); assert(sockfd != -1); struct sockaddr_in ser,cli; ser.sin_family = AF_INET; ser.sin_port = htons(6000); ser.sin_addr.s_addr = inet_addr("127.0.0.1"); int res = bind(sockfd,(struct sockaddr*)&ser,sizeof(ser)); assert(res != -1); listen(sockfd,5); int len = sizeof(cli); int c = accept(sockfd,(struct sockaddr*)&cli,&len); assert(c != -1); char buff[128] = {0}; recv(c,buff,127,0); printf("recv::%s\n",buff); send(c,"I Know",strlen("I Know"),0); close(c); close(sockfd); }
//客户端cli.cvoid main() { int sockfd = socket(AF_INET,SOCK_STREAN,0); assert(sockfd != -1); struct sockaddr_in ser,cli; ser.sin_family = AF_INET; ser.sin_port = htons(6000); ser.sin_addr.s_addr = inet_addr("127.0.0.1"); int res = connect(sockfd,(struct sockaddr*)&ser,sizeof(ser)); assert(res != -1); send(sockfd,"Hello World",strlen("Hello World"),0); char buff[128] = {0}; recv(sockfd,buff,127,0); printf("recv::%s\n",buff); close(sockfd); }
但是在实际应用中,服务器发送一次并没有结束,客户端可以一直申请,因此服务器端要循环收发数据。
void main() { int sockfd = socket(AF_INET,SOCK_STREAM,0); assert(sockfd != -1); struct sockaddr_in ser,cli; ser.sin_family = AF_INET; ser.sin_port = htons(6000); ser.sin_addr.s_addr = inet_addr("127.0.0.1"); int res = bind(sockfd,(struct sockaddr*)&ser,sizeof(ser)); assert(res != -1); listen(sockfd,5); while(1) { int len = sizeof(cli); int c = accept(sockfd,(struct sockaddr*)&cli,&len); assert(c != -1); char buff[128] = {0}; recv(c,buff,127,0); printf("recv::%s\n",buff); send(c,"I Know",strlen("I Know"),0); close(c); } close(sockfd); }
阅读全文
0 0
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- <学习html>第三天笔记-链接标签;锚点定位、<base />标签;遇到标签之间关系的问题及解决方法
- [51Nod 1920] 空间统计学
- opencv3实现简单的数字图像识别(KNN)
- Hibernate4 更新删除
- Gym
- 网络编程
- 快速排序(Quick-Sort)
- VS2013+QT+OPENGL+Eigen+Cmake配置方法
- C#中Socket通信用法实例详解
- 分治法,贪心算法,动态规划算法总结(斯坦福算法课Algorithms:Design and Analysis Part2)
- [KMP fail树] BZOJ3670: [Noi2014]动物园
- Eclipse中创建新的Spring Boot项目
- 自己动手实现一个mvvm库
- Printf函数与Scanf函数学习