Linux C : TCPIP 和 网络编程

本文详细介绍了TCP/IP的基础知识,包括IP主机、IP地址、IP数据包格式和TCP/IP数据流。重点讲解了套接字编程,涵盖创建、绑定、UDP和TCP套接字的使用。此外,还提供了UDP回显和TCP回显服务器-客户机程序的示例代码,深入解析了服务器端和客户端的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、IP主机和IP地址

二、IP数据包格式

三、TCP/IP在网络中的数据流

四、套接字编程

4.1 创建套接字

4.2绑定socket和端口号?

4.3、UDP 套接字

4.4 TCP 套接字

?五、 UDP回显? 服务器-客户机程序

六、TCP 回显服务器-客户机


TCP/IP 是互联网的基础, TCP代表传输控制协议,IP代表互联网协议。目前有两个版本IP,一个是32位地址的IPv4 和一个是128位的 IPv6 。而IPv4 是现如今使用最多的IP版本,也是这次讨论的重点。

一、IP主机和IP地址

每一个注意由一个32位的IP地址来标识。为了方便起见,通常用32位的IP低质号用记点法标识例如:134.121.64.1 也可以用主机名标识如 dns1.eec.wsu.edu 。实际上应用程序通常使用主机名而不是IP地址。因为给定其中一个,我们都可以通过dns(域名系统)服务器找到另外一个,两者之间可以相互转换。

IP地址分为两部分 NeiworkID 和 HostID 字段。其中,IP 可以分为A~E类。例如B类IP分为一个16位NeiworkID,前两位是10 。发往UP地址的数据包首先被发送到具有相同networkID的路由器默认IP地址位127.0.0.1.

二、IP数据包格式

IP数据包由IP头、发送方IP地址、接收方IP地址和数据组成。每个IP数据包的大小最大为64K。IP头包含有关数据包的信息。内容如下:

IP主机可能距离很远通常不可能从一个主机直接向另一个主机发送数据包。路由器是转发数据包的特殊IP主机,它可以向普通IP主机和其他路由器发送数据包,

三、TCP/IP在网络中的数据流

应用层的数据被传到传输层会添加TCP 或者UDP包头来标识使用的传输协议。合并后的数据被传到IP网络层,添加一个包含IP地址的IP报头来标识发送和接收主机。然后合并后的数据传递到网络链路层,再次将数据分成多个帧,添加发送和接收网络的地址,用于在物理网络之间的传输。

四、套接字编程

在 netdb.h 和 sys/socket.h中有套接字的地址结构定义

struct sockaddr_in {
   sa_family_t sin_family;  //TCP/IP网络的sin_family 始终设置为AF_INET
   in_port_t sin_port;       //包含网络字节顺序排列的端口号
   struct in_addr sin_addr ;   //按网络字节顺序排列的IP地址
}

struct in_addr{        
   unit32_t s_addr;     //按网络字节顺序排列的IP地址
}

服务器套接字编程步骤如下

  1. 创建socket;
  2. 绑定socket和端口号;
  3. 监听端口号; (UDP省略)
  4. 接收来自客户端的连接请求;(UDP省略)
  5. 从socket中读取字符;
  6. 发送消息回客户机。

客户端套接字编程步骤如下

  1. 创建socket;
  2. 连接指定计算机的端口; (UDP省略)
  3. 向socket中写入信息;
  4. 从服务器接收消息。

4.1 创建套接字

int  socket(int domain, int type, int protocol);

domain参数

参数含义

AF_INET

IPv4协议

AF_INET6

Ipv6协议

AF_LOCAL

Unix协议域/只在本机内通信的套接字

AF_ROUTE

路由套接字

AF_KEY

秘钥套接字

type参数

参数含义

SOCK_STREAM

字节流套接字 (TCP)

SOCK_DGRAM

数据报套接字 (UDP)

SOCK_SEQPACKET

有序分组套接字

SOCK_RAW

原始套接字

4.2绑定socket和端口号

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

bind系统调用将addr指定的地址分配文件描述符 sockfd所引用的套接字,addrlen指定addr所指向地址结构的大小对于用于联系其他UDP服务器主机的UDP套接字,必须绑定到客户机地址,允许服务器发回应答。对于接收客户机的TCP套接字,必须先将其绑定到服务器主机地址。

4.3、UDP 套接字

将缓冲区中len字节数据发送到dest_addr标识的目标主机

ssize_t sendto(int fd, const void *buf,size_t len,int flags,const struct sockaddr *dest_addr,socklen_t tolen);

从缓冲区中len字节数接收数据

ssize_t recvfrom(int fd, void *buf, size_t len,int flags,struct sockaddr *src_addr, socklen_t *len);

4.4 TCP 套接字

在绑定socket 和端口号后 TCP服务器用 listen 和 accpet 来监听、接受客户机的连接

//backlog 定义了等待连接的最大长度
int listen(int sockfd, int backlog);


//提取等待连接队列上的第一个连接请求同于监听sockfd,执行时造成进程阻塞,直到客户机通过connect建立连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //  返回新的文件描述符

//如果sockfd 时SOCK_DGRAM (USD 套接字)类型时,addr时发送数据报的默认地址,也是接收数据报的唯一地址。如果时 SOCK_STREAM (TCP 套接字)类型时,connect连接到绑定到addr指定的套接字
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

发送/接收数据

可以使用 send/read 或者 recv/write 来接收和发送数据。

read 和 write 是对文件描述符的读取和写入

//对已经连接的fd 发送数据 ,flags 通常是0 
ssize_t send(int fd , const void *buf , size_t len , int flags);

//对已经连接的fd 接收数据 ,flags 通常是0 
ssize_t recv(int fd , void *buf , size_t len , int flags);

五、 UDP回显 服务器-客户机程序

服务器端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFLEN 256
#define PORT 1234

char line[BUFLEN];
struct sockaddr_in me ,client;
int sock ,rlen=sizeof(client);
socklen_t clen   = sizeof (client);

int main (){
	printf("1. create a UDP socket
");
	sock = socket (AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	printf("2. fill me with server address and port number 
");
	memset((char *) & me ,0,sizeof(me));
	me.sin_family = AF_INET;
	me.sin_port   =  htons(PORT);
	me.sin_addr.s_addr = htonl(INADDR_ANY);
	printf("3.  bind socket to server IP and port 
");
	bind (sock ,(struct sockaddr *) & me ,sizeof (me));
	printf("4. wait for datagram 
");
	while (1){
		memset(line ,0,BUFLEN);
		printf("UDP server:waiting for datagram 
");
		rlen =recvfrom (sock , line , BUFLEN,0,(struct sockaddr *)&client ,&clen);
		printf("received a datagram from [host : prot] =[%s :%d] 
", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
		printf("rlen=%d:line%s 
",rlen,line);
		printf("send reply 
");
		sendto (sock ,line,rlen,0,(struct sockaddr*)&client,clen);
		printf("------------------------
");
	}

}

UDP客户机端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFLEN 256
#define SERVER_PORT 1234
#define SERVER_HOST "127.0.0.1"
char line[BUFLEN];
struct sockaddr_in server;
int sock ,rlen,slen   = sizeof (server);

int main (){
	printf("1. create a UDP socket
");
	sock = socket (AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	printf("2. fill in server address and port number 
");
	memset((char *) & server ,0,sizeif(server));
	server.sin_family = AF_INET;
	server.sin_port   =  htons(SERVER_PORT);
	inet_aton(SERVER_PORT , &server.sin_addr);
	while(1){
		printf("Enter a line: 
");	
		fget(line,BUFLEN,stdin);
		line[strlen(line) -1 ]=0;
		printf("send a line to server 
");
		sendto(sock,line,strlen(len),0,(struct sockaddr *)&server,slen);
		memset(line ,0 ,BUFLEN);
		printf("try to receive a line from server 
");
		rlen =recvfrom (sock,line,BUFLEN,0,(struct sockaddr *)&server,slen);
		printf("rlen =%d : line=%s 
" ,rlen ,line);
	}
	
}

六、TCP 回显服务器-客户机

服务器端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include<unistd.h>
#define MAX 256
#define SERVER_IP "127.0.0.1"
#define SERVER_HOST "localhost"
#define SERVER_PORT 1234

struct sockaddr_in server_addr ,client_addr;
int mysock,csock;    //sock的文件描述符
int r,n;       //辅助变量
socklen_t len;
int server_init(){
	printf("=============server init========
");
	printf("1. create a TCP socket
");
	mysock = socket (AF_INET,SOCK_STREAM,0);
	if(mysock < 0){
		printf("socket call failed
"); exit(1);
	}
	printf("2. fill server_addr with host_ip and port number 
");
	
	server_addr .sin_family = AF_INET;
	server_addr .sin_port   =  htons(SERVER_PORT);
	server_addr .sin_addr.s_addr = htonl(INADDR_ANY);
	printf("3.  bind socket to server address 
");
	r =bind (mysock ,(struct sockaddr *) & server_addr  ,sizeof (server_addr ));
	if( r<0){
		printf("bind call failed
"); exit(3);
	}
	printf("	hostname =%s, port = %d 
", SERVER_HOST ,SERVER_PORT);
	listen(mysock , 5 );
	printf("============init done ===========
");
	return 0;
}

int main (){
	char line [MAX];
	server_init();
	while (1){
		printf("server accepting new connection... 
");
		len = sizeof(client_addr);
		csock =  accept(mysock,(struct sockaddr *)&client_addr,&len);	
		if(csock <0){
			printf("accept failed
"); exit(1);
		}
		printf("Server: accept a client :IP=%s , port = %d 
",
		          inet_ntoa(client_addr.sin_addr) ,
		          ntohs(client_addr.sin_port));	
		while(1){
			n=read(csock,line,MAX);
			if(n=0) {
				printf("clinet dead ,server loop
");
				close(csock); break;
			}
			printf("read n =%d byte;line = %s 
", n,line);
			n=write(csock,line,MAX);
			printf("write n =%d byte;ECHO = %s 
", n,line);
			printf("ready for next request
");
		}
	}

}

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<unistd.h>

#define MAX 256
#define SERVER_HOST "localhost"
#define SERVER_PORT 1234


struct sockaddr_in server_addr ;
int sock,r;   

int client_init(){
	printf("=============client init========
");
	printf("1. create a TCP socket
");
	sock = socket (AF_INET,SOCK_STREAM,0);
	if(sock < 0){
		printf("socket call failed
"); exit(1);
	}
	printf("2. fill server_addr with host_ip and port number 
");
	
	server_addr .sin_family = AF_INET;
	server_addr .sin_port   =  htons(SERVER_PORT);
	server_addr .sin_addr.s_addr = htonl(INADDR_ANY);
	printf("3.  connecting to server 
");
	r = connect (sock ,(struct sockaddr *) & server_addr  ,sizeof (server_addr ));	
	if( r<0){
		printf("bind call failed
"); exit(3);
	}
	printf("	hostname =%s, port = %d 
", SERVER_HOST ,SERVER_PORT);
	printf("============client init done ===========
");
	return 0;
}

int main (){
	char line [MAX] , ans[MAX];
	int n; 
	client_init();
	printf(" ********processing loop *******************");
	while (1){
		printf("put a line... 
");
		bzero(line ,MAX);
		fgets(line,MAX,stdin);
		line[strlen(line) - 1] = 0;
		if(line[0] ==0) exit(0);
		n=write(sock,line,MAX);
		printf("client : wrote n =%d bytes ; line %s :
", n , line);
		n =read(sock ,ans,MAX);	
		printf("client : read n =%d bytes ; line %s :
", n , line);
	}

}

在Internet普及的今天,作为Internet工作基础的TCP/IP协议及其编程已经成了IT人业人员所要具备的基本知识与技能。打开国内外各大知名网站的招聘页面,都可以看到类似于“熟悉TCP/IP协议、掌握socket通讯开发”等字样的要求。本书就是为了满足读者在这方面知识的需求而编写的一本TCP/IP协议与基于TCP/IP编程方面的书籍。 本书有以下几个方面的特点: (1)内容的组织上按照协议原理与协议编程分为上、下篇。上篇主要介绍TCP/IP协议簇中的常用协议,下篇专门介绍网络编程知识与技能。 (2)具体在编写每一节的内容时将原理知识与实用技能融为一体。以方便读者学习。 (3)考虑到TCP/IP协议比较抽象,学习起来有一定的难度,所以全书尽量避免使用晦涩难懂专业术语,而用浅显易懂的语言说明问题,努力将书打造成一本人人都读懂书籍。 (4)初学网络程序设计的人员,往往感到网络程序设计内容多,学习进来比较复杂。针对这一问题,本书在讲解网络程序设计时,根据网络程序固有的特点,先总结了网络程序设计的通用模式,然后再举例说明网络程序的设计,使读者易于入手。 (5)Winsock函数内容多,使用起来比较复杂,针对这一问题,笔者在写作时将常用的Winsock函数分散到各种实例中去介绍,然后在最后一章将所有常用的Winsock函数一一作了较为详细说明,并在每个函数后面加入了其应用实例或使用说明。 本书分为上、下两篇内容,上篇内容包含6章,各章主要如下: 第1章:介绍了TCP/IP协议的产生、结构工作原理,另外本章内容中还简要介绍一一下ISO/OSI RM。 第2章:介绍TCP/IP协议层次结构中网络接口层包含的内容,主要有物理层数据链路的相关知识。 第3章:介绍TCP/IP协议层次结构中网络层及其相关知识。主要内容有IP数据报格式、IP层的功能、IP地址、ICMP协议、地址转换协议并介绍了IP的最新版本IP v6等。 第4章:介绍TCP/IP协议层次结构中传输层及其相关知识。主要内容有端口的概念、TCP协议UDP协议的协议数据格式、协议原理TCP协议与UDP协议的比较等内容。 第5章:介绍TCP/IP协议层次结构中应用层及其相关知识。主要内容有应用层常用协议DNS、FTP、Telnet、HTTP、POPSMTP的格式、工作原理、协议实例等内容。 第6章:简要的介绍了一下TCP/IP协议在WindowsLINUX操作系统下的实现原理TCP/IP协议的二进制代码。 下篇包含以下6章内容: 第7章:介绍了网络程序设计有关的基础知识、一个网络程序入门实例Winsock中编写网络程序常用的建立连接、传输数据、关闭连接等有关的函数。 第8章:介绍了TCP程序设计流程、基于C/C++的TCP程序设计实例基于Java技术的TCP程序设计实例。 第9章:介绍了UDP程序设计流程、基于C/C++的UDP程序设计实例基于Java技术的UDP程序设计实例。 第10章:介绍了使用MFC中提供的有关类进行网络程序设计知识。 第11章:介绍了Winsock API中各种函数的功能,并举例说明了些函数的使用方法。 本书在编写过程中得到了邮电出版刘博等编辑的大力支持帮助,在此表示感谢。由于作者水平有限,错漏之处在所难免,欢迎广大读者批评指正提出宝贵的意见,可发邮件到。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bluepad

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值