10、网络基础和SOCKET
1、TCP/IP协议概述
- TCP/IP是互联网的基础
- OSI参考模型与TCP/IP参考模型对应关系:
- TCP/IP 实际上是一个一起工作的通信家族,为网际数据通信提供通路。为讨论方便可将
- TCP/IP 协议组大体上分为三部分:
- 1.Internet 协议(IP)
- 2.传输控制协议(TCP)和用户数据报文协议(UDP)
- 3.处于TCP 和UDP 之上的一组协议专门开发的应用程序。它们包括:TELNET,文件传送协议(FTP),域名服务(DNS)和简单的邮件传送程序(SMTP)等许多协议。
2、传输层协议 - TCP(传输控制协议)
- 传输层协议。包括传输控制协议TCP和用户数据报文协议UDP。
- 传输控制协议(TCP)。由于IP 提供非连接型传递服务,因此TCP应为应用程序存取网络创造了条件,使用可靠的面向连接的传输层服务。该协议为建立网际上用户进程之间的对话负责。此外,还确保两个以上进程之间的可靠通信。它所提供的功能如下:
- 1.监听输入对话建立请求。
- 2.请求另一网络站点对话。
- 3.可靠的发送和接收数据。
- 4.适度的关闭对话。
三次握手
- 1、初始化主机通过一个同步标志置位的数据段发出会话请求。
- 2、接收主机通过发回具有以下项目的数据段表示回复:同步标志置位、即将发送的数据段的起始字节的顺序号、应答并带有将收到的下一个数据段的字节顺序号。
- 3、请求主机再回送一个数据段,并带有确认顺序号和确认号。
3、传输层协议 - UDP(用户数据报文协议)
- 用户数据报文协议(UDP)。UDP 提供不可靠的非连接型传输层服务,它允许在源和目的地站点之间传送数据,而不必在传送数据之前建立对话。此外,该协议还不使用TCP使用的端对端差错校验。当使用UDP时,传输层功能全都发挥,而开销却比较低。它主要用于那些不要求TCP协议的非连接型的应用程序。例如,名字服务、网络管理、视频点播和网络会议等。
4、应用层协议
- Telnet
- 文件传送协议(FTP 和TFTP)
- 简单的邮件传送协议(SMTP)
- 域名服务(DNS)等协议。
5、网络编程基础
socket概述
- 为了简化开发通信程序的工作,由Berkely学校开发了一套网络通信程序的API函数标准
- socket标准被扩展成window socket和unix socket
- linux中的网络编程通过socket接口实现。Socket既是一种特殊的IO,它也是一种文件描述符。一个完整的Socket 都有一个相关描述{协议,本地地址,本地端口,远程地址,远程端口};每一个Socket 有一个本地的唯一Socket 号,由操作系统分配。
SOCKET分类
- 流式套接字(SOCK_STREAM)
- 流式的套接字可以提供可靠的、面向连接的通讯流。它使用了TCP协议。TCP 保证了数据传输的正确性和顺序性。
- 数据报套接字(SOCK_DGRAM)
- 数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。使用数据报协议UDP协议。
- 原始套接字
- 原始套接字允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等。
套接字地址结构
struct sockaddr{
unsigned short sa_family; /* address族, AF_xxx */
char sa_data[14]; /* 14 bytes的协议地址 */
};
//sa_family 一般来说, IPV4使用“AF_INET”。
//sa_data 包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一起的。
sockaddr_in地址结构
struct sockaddr_in {
short int sin_family; /* Internet地址族 */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* Internet地址 */
unsigned char sin_zero[8]; /* 添0(和struct sockaddr一样大小)*/
};
字节序列转换
- 因为每一个机器内部对变量的字节存储顺序不同(有的系统是高位在前,底位在后,而有的系统是底位在前,高位在后 ),而网络传输的数据大家是一定要统一顺序的。所以对与内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换。
字节转换函数
-
htons()——“Host to Network Short”
主机字节顺序转换为网络字节顺序(对无符号短型进行操作2bytes)
-
htonl()——“Host to Network Long”
主机字节顺序转换为网络字节顺序(对无符号长型进行操作4bytes)
-
ntohs()——“Network to Host Short”
网络字节顺序转换为主机字节顺序(对无符号短型进行操作2bytes)
-
ntohl()——“Network to Host Long ”
网络字节顺序转换为主机字节顺序(对无符号长型进行操作4bytes)
地址格式转换
- linux提供将点分格式的地址转于长整型数之间的转换函数。
- inet_addr()能够把一个用数字和点表示IP 地址的字符串转换成一个无符号长整型。
- inet_ntoa()
- inet_aton()
基本套接字调用
socket() bind() connect()
listen() accept() send()
recv() sendto() shutdown()
recvfrom() close() getsockopt()
setsockopt() getpeername()
getsockname() gethostbyname()
gethostbyaddr() getprotobyname()
fcntl()
基于流套接字的编程流程
6、socket示例
//server.cpp
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#define PORT 0x8888
int main(int argc,char *argv[])
{
int sfp,nfp;
static int number=0;
struct sockaddr_in s_add,c_add;
char buffer[1024]={0};
printf("Hello,welcome to my server!\n");
sfp=socket(AF_INET,SOCK_STREAM,0);
if(-1==sfp){
printf("socket fail!\n");
return -1;
}
printf("socket ok!\n");
bzero(&s_add,sizeof(struct sockaddr_in));
s_add.sin_family=AF_INET;
s_add.sin_addr.s_addr=htonl(INADDR_ANY);
s_add.sin_port=htons(PORT);
if(-1==bind(sfp,(struct sockaddr *)(&s_add),sizeof(struct sockaddr))){
printf("bind fail!\n");
return -1;
}
printf("bind ok!\n");
if(-1==listen(sfp,5)){
printf("listen fail!\n");
return -1;
}
printf("listen ok\n");
socklen_t addrlen = sizeof(struct sockaddr_in);
while(1){
nfp=accept(sfp,(struct sockaddr *)(&c_add),&addrlen);
if(-1==nfp){
printf("accept fail!\n");
return -1;
}
printf("accept ok!\nServer start get connect from %#x :%#x\n",ntohl(c_add.sin_addr.s_addr),ntohs(c_add.sin_port));
number++;
int ret=fork();
if(ret>0){
break;
}
}
while(1){
memset(buffer,0,sizeof(buffer));
int len=read(nfp,buffer,sizeof(buffer));
if(len>0){
printf("client_%d:%s\n",number,buffer);
write(nfp,buffer,sizeof(buffer));
}
}
close(sfp);
return 0;
}
//client.cpp
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 0x8888
int main(int argc,char *argv[])
{
int cfd;
int recbytes;
char buffer[1024]={0};
struct sockaddr_in s_add;
printf("Hello,welcome to client !\n");
cfd=socket(AF_INET,SOCK_STREAM,0);
if(-1==cfd){
printf("socket fail!\n");
return -1;
}
printf("socket ok!\n");
bzero(&s_add,sizeof(struct sockaddr_in));
s_add.sin_family=AF_INET;
s_add.sin_addr.s_addr=inet_addr("127.0.0.1");
s_add.sin_port=htons(PORT);
printf("s_addr=%#x,port : %#x\n",s_add.sin_addr.s_addr,s_add.sin_port);
if(-1==connect(cfd,(struct sockaddr *)(&s_add),sizeof(struct sockaddr))){
printf("connect fail!\n");
return -1;
}
printf("connect to server success!\n");
while(1){
memset(buffer,0,sizeof(buffer));
printf("please input:");
fgets(buffer,sizeof(buffer),stdin);
printf("\n");
write(cfd,buffer,sizeof(buffer));
memset(buffer,0,sizeof(buffer));
if(-1==(recbytes=read(cfd,buffer,1024))){
printf("read data fail!\n");
return -1;
}
if(recbytes>0){
printf("server:%s\n",buffer);
//buffer[recbytes]='\0';
//printf("%s\n",buffer);
}
}
getchar();
close(cfd);
return 0;
}