目录
前言:
这里呢说到了TCP协议就不得不提一下网络体系结构,所谓网络体系结构就是网络的分层结构和各层使用协议的集合。
OSI模型:
其中OSI模型是理想化的,它分为7层:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层;它划分的非常详细但是呢过于复杂,在实际中没有被广泛使用。
TCP/IP模型:
相反TCP/IP模型就相对使用就很广泛了,它分为4层:应用层,传输层,网络层,网络接口物理层;其实这里的应用层是把OSI模型的应用层,表示层,会话层归纳在一起,而网络接口物理层是把OSI模型去的数据链路层和物理层归纳在一起;从而利于实现和高效通信;
模型对应关系图:
各层的功能及协议:
1.网络接口物理层:
是TCP/IP的最底层,负责将二进制流转换为数据帧,并进行数据帧的发送和接收。数据帧是网络传输的基本单元。协议主要有ARP,RARP,PPP。
2.网络层:
负责在主机之间的通信中选择数据包的传输路径,即路由。还负责处理传入的数据包,检验其有效性,使用路由算法来决定对数据包进行本地处理和转发。所以有时称网络层的功能就是路由和转发;协议主要有:IP,ICMP,IGMP;
3.传输层:
负责实现应用程序之间的通信服务。协议主要有TCP,UDP,STCP。其中TCP和UDP是很重要的,TCP是面向有连接的高可靠的传输控制协议,UDP是面向无连接的不可靠的用户数据报协议。
4.应用层:
负责把封装好的数据交给传输层或者从传输层接收并处理数据。协议主要有:http,tftp。
套接字(Socket):
是一种特殊的I/O接口,也是一种文件描述符。Socket是常用的一种进程之间的通信机制,不仅能实现本地不同进程之间的通信,而且通过网络能在不同主机的进程之间进行通信;而套接字又分三种类型:
1,流式套接字(SOCK_STREAM):
流式套接字提供了可靠的,面向连接的通信流,保证数据传输的可靠性和按序收发。TCP通信就是使用的流式套接字。
2.数据报套接字(SOCK_DGRAM):
数据报套接字实现了一种不可靠的,无连接的服务。数据通过相互独立的报文进行传输,是无序的,并且不保证可靠的传输。UDP通信使用的就是数据报套接字。
3.原始套接字(SOCK_RAM):
原始套接字允许对底层协议进行直接访问,它功能强大但使用不方便,主要用于协议的开发。
Linux实现基于TCP协议的socket通信:
头文件:
#ifndef __NET_H
#define __NET_H
#include<string.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#endif
客户端:
#include<stdio.h>
#include"net.h"
#include<stdlib.h>
//请求连接服务器
int tcp_cliconnect(char*ip,int port)
{
int tcp_socket=socket(AF_INET,SOCK_STREAM,0);
if(tcp_socket<0)
{
perror("tcp_socket error");
return -1;
}
printf("socket success\n");
struct sockaddr_in client;
client.sin_family=AF_INET;
client.sin_addr.s_addr=inet_addr(ip);
client.sin_port=htons(port);
if(connect(tcp_socket,(struct sockaddr *)&client,sizeof(client))<0)
{
perror("connect faild");
return -1;
}
printf("connect success\n");
return tcp_socket;
}
//通过main函数传参,在执行时数入对应的IP地址和端口号
int main(int argc,char *argv[])
{
if(argc<3)
{
perror("argc error");
return -1;
}
int tcp_socket=tcp_cliconnect(argv[1],atoi(argv[2]));
if(tcp_socket<0)
{
return -1;
}
char buf[20]={0};
printf("write:");
fgets(buf,sizeof(buf),stdin);
send(tcp_socket,buf,strlen(buf),0);
close(tcp_socket);
return 0;
}
服务器端:
#include<stdio.h>
#include"net.h"
#include<stdlib.h>
//监听
int tcp_serconnect(char*ip,int port)
{
int tcp_socket=socket(AF_INET,SOCK_STREAM,0);
if(tcp_socket<0)
{
perror("tcp_socket error");
return -1;
}
printf("socket success\n");
struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_addr.s_addr=inet_addr(ip);
server.sin_port=htons(port);
if(bind(tcp_socket,(struct sockaddr *)&server,sizeof(server))<0)
{
perror("bind error");
return -1;
}
printf("bind success\n");
if(listen(tcp_socket,5)<0)
{
perror("listen error");
return -1;
}
printf("listen success\n");
return tcp_socket;
}
int main(int argc,char *argv[])
{
if(argc<3)
{
printf("argc error");
return -1;
}
int tcp_socket=tcp_serconnect(argv[1],atoi(argv[2]));
struct sockaddr_in client;
int len=sizeof(client);
//接受客户端的连接请求
int newtcp_socket=accept(tcp_socket,(struct sockaddr *)&client,&len);
if(newtcp_socket<0)
{
perror("accept faild");
return -1;
}
printf("accept success\n");
//打印对应的客户端的IP地址和端口号
printf("client ip=%s port=%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
char buf[20]={0};
recv(newtcp_socket,buf,sizeof(buf),0);
printf("%s",buf);
close(newtcp_socket);
close(tcp_socket);
return 0;
}