Bootstrap

LinuxIPC通信socket(C)

Internet-“冷战”的产物 1957年10月和11月,前苏联先后有两颗“Sputnik”卫星上天 1958年美国总统艾森豪威尔向美国国会提出建立DARPA (Defense Advanced Research Project Agency),即国防部高级研究计划署,简称ARPA 1968年6月DARPA提出“资源共享计算机网络” (Resource Sharing Computer Networks),目的在于让DARPA的所有电脑互连起来,这个网络就叫做ARPAnet,即“阿帕网”,是Interne的最早雏形

TCP协议分成了两个不同的协议: 用来检测网络传输中差错的传输控制协议TCP 专门负责对不同网络进行互联的互联网协议IP 从此,TCP/IP协议诞生 1983年ARPAnet上停止使用NCP,互联网上的主机全部使用TCP/IP协议。TCP/IP协议成为Internet中的“世界语”

网络采用分而治之的方法设计,将网络的功能划分为不同的模块,以分层的形式有机组合在一起。 每层实现不同的功能,其内部实现方法对外部其他层次来说是透明的。每层向上层提供服务,同时使用下层提供的服务 网络体系结构即指网络的层次结构和每层所使用协议的集合 两类非常重要的体系结构:OSI与TCP/IP

OSI模型相关的协议已经很少使用,但模型本身非常通用 OSI模型是一个理想化的模型,尚未有完整的实现 OSI模型共有七层

TCP/IP协议是Internet事实上的工业标准。 一共有四层

 

OSI模型与TCP/IP协议

 

TCP/IP分层

 

通信协议模型

数据的封装与传递

TCP(即传输控制协议)

打电话 是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信) 适用情况: 适合于对传输质量要求较高,以及传输大量数据的通信。 在需要可靠数据传输的场合,通常使用TCP协议 MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议

UDP(User Datagram Protocol)

用户数据报协议 是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。寄信 适用情况: 发送小尺寸数据(如对DNS服务器进行IP地址查询时) 在接收到数据,给出应答较困难的网络中使用UDP。(如:无线网络) 适合于广播/组播式通信中。 MSN/QQ/Skype等即时通讯软件的点对点文本通讯以及音视频通讯通常采用UDP协议 流媒体、VOD、VoIP、IPTV等网络多媒体服务中通常采用UDP方式进行实时数据传输

编程相关知识:

socket

Socket 是一个编程接口 是一种特殊的文件描述符 (everything in Unix is a file) 并不仅限于TCP/IP协议 面向连接 (Transmission Control Protocol - TCP/IP) 无连接 (User Datagram Protocol -UDP 和 Inter-network Packet Exchange - IPX)

流式套接字(SOCK_STREAM)

提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。

数据报套接字(SOCK_DGRAM)

提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。

原始套接字(SOCK_RAW)

可以对较低层次协议如IP、ICMP直接访问。

IP地址

Internet中主机的标识 Internet中的主机要与别的机器通信必须具有一个IP地址 IP地址为32位(IPv4)或者128位(IPv6) 每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由

端口号

为了区分一台主机接收到的数据包应该转交给哪个进程来进行处理,使用端口号来区别 TCP端口号与UDP端口号独立

端口号一般由IANA (Internet Assigned Numbers Authority) 管理

众所周知端口:1~1023(1~255之间为众所周知端口,256~1023端口通常由UNIX系统占用)

注册端口:1024~49150

动态或私有端口:49151~65535

字节序

不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO): 小端序(little-endian)  低序字节存储在低地址将低字节存储在起始地址,称为“Little-Endian”字节序,Intel、AMD等采用的是这种方式; 大端序(big-endian)  高序字节存储在低地址

关于socke的API函数详解在另外一篇博客里写了: https://blog.csdn.net/weixin_38452632

TCP:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc, char **argv)
{
	// 创建一个TCP套接字
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd == -1)
	{
		perror("socket failed");
		exit(0);
	}

	// 搞一个IPv4的地址结构体,并正确赋值
	struct sockaddr_in addr;
	bzero(&addr, sizeof(addr));
	addr.sin_family = AF_INET;
	inet_pton(AF_INET, "192.168.7.3", (void *)&addr.sin_addr);
	addr.sin_port = htons(50001);

	// 绑定号码
	bind(fd, (struct sockaddr *)&addr, sizeof(addr));

	// 设置监听状态
	// 3+4代表以后的最大同时链接请求个数
	listen(fd, 3);

	// 默默等待对方的链接请求
	// fd: 监听套接字
	// connfd: 读写套接字
	int connfd = accept(fd, NULL, NULL);

	char msg[100];
	while(1)
	{
		bzero(msg, 100);
		if (0 == read(connfd, msg, 100))
			break;
		
		printf("Jack: %s", msg);
	}
	close(fd);
	return 0;
}

 

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc, char **argv) // ./Jack 192.168.7.200 50001
{
	// 创建一个TCP套接字
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd == -1)
	{
		perror("socket failed");
		exit(0);
	}

	// 搞一个IPv4的地址结构体,并赋值为服务端的地址
	struct sockaddr_in srvaddr;
	bzero(&srvaddr, sizeof(srvaddr));
	srvaddr.sin_family = AF_INET;
	inet_pton(AF_INET, argv[1], (void *)&srvaddr.sin_addr);
	srvaddr.sin_port = htons(atoi(argv[2]));

	// 链接对方
	connect(fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));

	char msg[100];
	while(1)
	{
		bzero(msg, 100);
		fgets(msg, 100, stdin);

		if (0 == write(fd, msg, strlen(msg)))
			break;
	}

	close(fd);
	return 0;
}

UDP:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc, char **argv)
{
	// 创建一个UDP套接字
	int fd = socket(PF_INET, SOCK_DGRAM, 0);
	if(fd == -1)
	{
		perror("socket failed");
		exit(0);
	}

	// 搞一个IPv4的地址结构体,并正确赋值
	struct sockaddr_in addr;
	bzero(&addr, sizeof(addr));
	addr.sin_family = AF_INET;

	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(50001);

	// 绑定号码
	bind(fd, (struct sockaddr *)&addr, sizeof(addr));


	char msg[100];
	while(1)
	{
		bzero(msg, 100);
		recvfrom(fd, msg, 100, 0, NULL, NULL);

		printf("Jack: %s", msg);
	}

	return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc, char **argv) // ./Jack 192.168.7.200 50001
{
	// 创建一个UPP套接字
	int fd = socket(AF_INET, SOCK_DGRAM, 0);
	if(fd == -1)
	{
		perror("socket failed");
		exit(0);
	}

	// 搞一个IPv4的地址结构体,并赋值为服务端的地址
	struct sockaddr_in srvaddr;
	bzero(&srvaddr, sizeof(srvaddr));
	srvaddr.sin_family = AF_INET;
	inet_pton(AF_INET, argv[1], (void *)&srvaddr.sin_addr);
	srvaddr.sin_port = htons(atoi(argv[2]));


	char msg[100];
	while(1)
	{
		bzero(msg, 100);
		fgets(msg, 100, stdin);

		sendto(fd, msg, strlen(msg), 0,
			(struct sockaddr *)&srvaddr, sizeof(srvaddr));
	}

	return 0;
}

 

 

;