[Linux C编程]TCP网络通信

来源:互联网 发布:java清除jemetercookie 编辑:程序博客网 时间:2024/05/01 01:41

TCP网络通信

TCP编程模型

 

TCP/IP协议族

TCP/IP 实际上一个协同工作的通信家族,为网络数据通信提供通路。为讨论方便可TCP/IP 协议组大体上分为三部分:

1、Internet 协议(IP)

2、传输控制协议(TCP)和用户数据报协议(UDP)

3、处于 TCP 和 UDP 之上的一组应用协议。它们包括:TELNET,文件传送协议(FTP),域名服务(DNS)和简单的邮件传送程序(SMTP)等

网络层

第一部分称为网络层。主要包括Internet 协议(IP)、网际控制报文协议(ICMP)和地址解析协议(ARP)

·Internet 协议(IP)

该协议被设计成互联分组交换通信网,以形成一个网际通信环境。它负责在源主机和目的地主机之间传输来自其较高层软件的称为数据报文的数据块,它在源和目的地之间提供非连接型传递服务

·网际控制报文协议(ICMP)

它实际上不是IP层部分,但直接同IP层一起工作,报告网络上的某些出错情况。允许网际路由器传输差错信息或测试报文。

·地址解析协议(ARP)

ARP 实际上不是网络层部分,它处于IP和数据链路层之间,它是在32位IP地址和48位物理地址之间执行翻译的协议

传输层协议

第二部分是传输层协议,包括传输控制协议和用户数据报文协议

·传输控制协议(TCP):

该协议对建立网络上用户进程之间的对话负责,它确保进程之间的可靠通信,所提供的功能如下:

1.监听输入对话建立请求

2.请求另一网络站点对话

3.可靠的发送和接收数据

4.适度的关闭对话

·用户数据报文协议(UDP):

UDP 提供不可靠的非连接型传输层服务,它允许在源和目的地之间传送数据,而不必在传送数据之前建立对话。它主要用于那些非连接型的应用程序,如:视频点播

应用协议层

这部分主要包括Telnet,文件传送协议(FTP 和TFTP),简单文件传送协议(SMTP)和域名服务(DNS)等协议

IP 协议

IP主要有以下四个主要功能:

数据传送

寻址

路由选择

数据报文的分段

IP的主要目的是为数据输入/输出网络提供基本算法,为高层协议提供无连接的传送服务.这意味着在IP将数据递交给接收站点以前不在传输站点和接收站点之间建立对话。它只是封装和传递数据,但不向发送者或接收者报告包的状态,不处理所遇到的故障。

 

TCP协议

TCP是重要的传输层协议,目的是允许数据同网络上的其他节点进行可靠的交换。它能提供端口编号的译码,以识别主机的应用程序,而且完成数据的可靠传输TCP 协议具有严格的内装差错检验算法确保数据的完整性TCP 是面向字节的顺序协议,这意味着包内的每个字节被分配一个顺序编号,并分配给每包一个顺序编号

TCP协议头

 

UDP

 UDP也是传输层协议,它是无连接的,不可靠的传输服务.当接收数据时它不向发送方提供确认信息,它不提供输入包的顺序,如果出现丢失包或重份包的情况,也不会向发送方发出差错报文.由于它执行功能时具有较低的开销,因而执行速度比TCP快

UDP协议头

 

网络基础—套接字

·是一种特殊的IO接口,是一种文件描述符;

·是一种常用的进程之间的通信,本地,不同主机之间通信;

·Socket可用网络地址结构

·{协议,本地地址,本地端口}表示。

1.流式套接字SOCK_STREAM

提供可靠的、面向连接的通信流,保证数据传输的可靠性和按序收发。TCP属于流式;

2. 数据报套接字SOCK_DGRAM

不可靠,无连接的服务。UDP

3. 原始套接字SOCK_RAM

对底层协议进行访问,不方便,对一些协议开发。

 

套接字(socket)概述

套接字定义

在Linux中的网络编程是通过socket接口来进行的。套接字(socket)是一种特殊的I/O接口,它也是一种文件描述符。

 

socket是一种常用的进程之间通信机制,通过它不仅能实现本地机器上的进程之间的通信,而且通过网络能够在不同机器上的进程之间进行通信。

每一个socket都用一个半相关描述:

             {协议、本地地址、本地端口}来表示;

一个完整的套接字则用一个相关描述:

            {协议、本地地址、本地端口、远程地址、远程端口}来表示。

socket也有一个类似于打开文件的函数调用,该函数返回一个整型的socket描述符,

随后的连接建立、数据传输等操作都是通过socket来实现的。

 

IP地址格式转换

两种形式:十进制点分形式,32位二进制形式。

IPV4地址转换函数:

·Inet_aton(),inet_addr(),  inet_ntoa()

 

IPV4 ,IPV6兼容:

·Inet_pton(), inet_ntop();

 

十进制点分形式转换成二进制形式:

Inet_addr(),  inet_pton();

 

二进制地址转换成十进制点分形式:

Inet_ntop()

Inet_addr()函数

函数作用:十进制转换成二进制

函数原型:Int inet_addr(const char *strptr);

参数:Strptr:要转换的IP地址字符串

返回值:成功:32位二进制IP地址(网络字节序)

        出错:-1

 

使用TCP时Socket编程


socket()函数语法

 

bind()函数语法:

 

listen()函数语法:

 

accept()函数语法:

 

connect()函数语法:

 

send()函数语法:

 

recv()函数语法:

 

sendto()函数语法:

 

recvfrom()函数语法:

 

贴个例程吧~大家可以看看到底具体是怎么搭建TCP网络通信的!

tcp_client.c

<pre name="code" class="html">#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #define portnumber 3333int main(int argc, char *argv[]) { int sockfd; char buffer[1024]; struct sockaddr_in server_addr; struct hostent *host;         /* 使用hostname查询host 名字 */if(argc!=2) { fprintf(stderr,"Usage:%s hostname \a\n",argv[0]); exit(1); } if((host=gethostbyname(argv[1]))==NULL) { fprintf(stderr,"Gethostname error\n"); exit(1); } /* 客户程序开始建立 sockfd描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) // AF_INET:Internet;SOCK_STREAM:TCP{ fprintf(stderr,"Socket Error:%s\a\n",strerror(errno)); exit(1); } /* 客户程序填充服务端的资料 */ bzero(&server_addr,sizeof(server_addr)); // 初始化,置0server_addr.sin_family=AF_INET;          // IPV4server_addr.sin_port=htons(portnumber);  // (将本机器上的short数据转化为网络上的short数据)端口号server_addr.sin_addr=*((struct in_addr *)host->h_addr); // IP地址/* 客户程序发起连接请求 */ if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) { fprintf(stderr,"Connect Error:%s\a\n",strerror(errno)); exit(1); } /* 连接成功了 */ printf("Please input char:\n");/* 发送数据 */fgets(buffer,1024,stdin); write(sockfd,buffer,strlen(buffer)); /* 结束通讯 */ close(sockfd); exit(0); } 


tcp_server.c

#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #define portnumber 3333int main(int argc, char *argv[]) { int sockfd,new_fd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size; int nbytes;char buffer[1024];/* 服务器端开始建立sockfd描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) // AF_INET:IPV4;SOCK_STREAM:TCP{ fprintf(stderr,"Socket error:%s\n\a",strerror(errno)); exit(1); } /* 服务器端填充 sockaddr结构 */ bzero(&server_addr,sizeof(struct sockaddr_in)); // 初始化,置0server_addr.sin_family=AF_INET;                 // Internetserver_addr.sin_addr.s_addr=htonl(INADDR_ANY);  // (将本机器上的long数据转化为网络上的long数据)和任何主机通信  //INADDR_ANY 表示可以接收任意IP地址的数据,即绑定到所有的IP//server_addr.sin_addr.s_addr=inet_addr("192.168.1.1");  //用于绑定到一个固定IP,inet_addr用于把数字加格式的ip转化为整形ipserver_addr.sin_port=htons(portnumber);         // (将本机器上的short数据转化为网络上的short数据)端口号/* 捆绑sockfd描述符到IP地址 */ if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) { fprintf(stderr,"Bind error:%s\n\a",strerror(errno)); exit(1); } /* 设置允许连接的最大客户端数 */ if(listen(sockfd,5)==-1) { fprintf(stderr,"Listen error:%s\n\a",strerror(errno)); exit(1); } while(1) { /* 服务器阻塞,直到客户程序建立连接 */ sin_size=sizeof(struct sockaddr_in); if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1) { fprintf(stderr,"Accept error:%s\n\a",strerror(errno)); exit(1); } fprintf(stderr,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr)); // 将网络地址转换成.字符串if((nbytes=read(new_fd,buffer,1024))==-1) { fprintf(stderr,"Read Error:%s\n",strerror(errno)); exit(1); } buffer[nbytes]='\0';printf("Server received %s\n",buffer);/* 这个通讯已经结束 */ close(new_fd); /* 循环下一个 */ } /* 结束通讯 */ close(sockfd); exit(0); } 


0 0