Linux C : TCPIP 和 网络编程

目录

一、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);
	}

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
教程非常不错,价值280元,绝对是干货 Linux网络编程(总共41集) 讲解Linux网络编程知识,分以下四个篇章。 Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念(对等通信、封装、分用、端口) 02TCPIP基础(二) 最大传输单元(MTU)/路径MTU 以太网帧格式 ICMP ARP RARP 03TCPIP基础(三) IP数据报格式 网际校验和 路由 04TCPIP基础(四) TCP特点 TCP报文格式 连接建立三次握手 连接终止四次握手 TCP如何保证可靠性 05TCPIP基础(五) 滑动窗口协议 UDP特点 UDP报文格式 Linux网络编程之socket编程篇 06socket编程(一) 什么是socket IPv4套接口地址结构 网络字节序 字节序转换函数 地址转换函数 套接字类型 07socket编程(二) TCP客户/服务器模型 回射客户/服务器 socket、bind、listen、accept、connect 08socket编程(三) SO_REUSEADDR 处理多客户连接(process-per-conection) 点对点聊天程序实现 09socket编程(四) 流协议与粘包 粘包产生的原因 粘包处理方案 readn writen 回射客户/服务器 10socket编程(五) read、write与recv、send readline实现 用readline实现回射客户/服务器 getsockname、getpeername gethostname、gethostbyname、gethostbyaddr 11socket编程(六) TCP回射客户/服务器 TCP是个流协议 僵进程与SIGCHLD信号 12socket编程(七) TCP 11种状态 连接建立三次握手、连接终止四次握手 TIME_WAIT与SO_REUSEADDR SIGPIPE 13socket编程(八) 五种I/O模型 select 用select改进回射客户端程序 14socket编程(九) select 读、写、异常事件发生条件 用select改进回射服务器程序。 15socket编程(十) 用select改进第八章点对点聊天程序 16socket编程(十一) 套接字I/O超时设置方法 用select实现超时 read_timeout函数封装 write_timeout函数封装 accept_timeout函数封装 connect_timeout函数封装 17socket编程(十二) select限制 poll 18socket编程(十三) epoll使用 epoll与select、poll区别 epoll LT/ET模式 19socket编程(十四) UDP特点 UDP客户/服务基本模型 UDP回射客户/服务器 UDP注意点 20socket编程(十五) udp聊天室实现 21socket编程(十六) UNIX域协议特点 UNIX域地址结构 UNIX域字节流回射客户/服务 UNIX域套接字编程注意点 22socket编程(十七) socketpair sendmsg/recvmsg UNIX域套接字传递描述符字 Linux网络编程之进程间通信篇 23进程间通信介绍(一) 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) 消息队列 IPC对象数据结构 消息队列结构 消息队列在内核中的表示 消息队列函数 26System V消息队列(二) msgsnd函数 msgrcv函数 27System V消息队列(三) 消息队列实现回射客户/服务器 28共享内存介绍 共享内存 共享内存示意图 管道、消息队列与共享内存传递数据对比 mmap函数 munmap函数 msync函数 29System V共享内存 共享内存数据结构 共享内存函数 共享内存示例 30System V信号量(一) 信号量 信号量集结构 信号量集函数 信号量示例 31System V信号量(二) 用信号量实现进程互斥示例 32System V信号量(三) 用信号集解决哲学家就餐问题 33System V共享内存与信号量综合 用信号量解决生产者消费者问题 实现shmfifo 34POSIX消息队列 POSIX消息队列相关函数 POSIX消息队列示例 35POSIX共享内存 POSIX共享内存相关函数 POSIX共享内存示例 Linux网络编程之线程篇 36线程介绍 什么是线程 进程与线程 线程优缺点 线程模型 N:1用户线程模型 1:1核心线程模型 N:M混合线程模型 37POSIX线程(一) POSIX线程库相关函数 用线程实现回射客户/服务器 38POSIX线程(二) 线程属性 线程特定数据 39POSIX信号量与互斥锁 POSIX信号量相关函数 POSIX互斥锁相关函数 生产者消费者问题 自旋锁与读写锁介绍 40POSIX条件变量 条件变量 条件变量函数 条件变量使用规范 使用条件变量解决生产者消费者问题 41一个简单的线程池实现 线程池性能分析 线程池实现 网络编程, Linux, 密码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bluepad

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

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

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

打赏作者

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

抵扣说明:

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

余额充值