网络模型 | osi 参考模型,tcp/ip 参考模型 |
网络通讯要素 | ip地址,端口号,传输协议
IP地址就是我想找到他的主机地址,但是如何区分是feiq 找他还是qq 找他用端口号区分,每一种进程的端口号是不同的 |
Socket 编程浏览器的进程怎么与web服务器通信的,当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信,这些都得靠socket,那什么是socket?socket的类型有哪些?还有socket的基本函数,进程间通讯要遵循tcp/ip 协议 socket是“open—write/read—close”模式的一种实现 Socket 就是网络服务提供的一种机制,通信的两端都有socket,网络通信其实就是socket 通信,数据在两个socket 间通过io 传输 | |
网络中的进程如何通信 | 本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类:
消息传递(管道、FIFO、消息队列) 同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量) 共享内存(匿名的和具名的) 远程过程调用(Solaris门和Sun RPC) |
int socket(int domain, int type, int protocol); | socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。 正如可以给fopen的传入不同参数值,以打开不同的文件。创建socket的时候,也可以指定不同的参数创建不同的socket描述符,socket函数的三个参数分别为: ·domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。 |
accept()函数 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
| TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。 accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。 注意:accept的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept函数返回的是已连接的socket描述字。一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。 |
read()、write()等函数
| 万事具备只欠东风,至此服务器与客户已经建立好连接了。可以调用网络I/O进行读写操作了,即实现了网咯中不同进程之间的通信!网络I/O操作有下面几组:read()/write() recv()/send() readv()/writev()recvmsg()/sendmsg()recvfrom()/sendto()其它的我就不一一介绍这几对I/O函数了,具体参见man文档或者baidu、Google,下面的例子中将使用到send/recv。 |
close()函数
| 在服务器与客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的socket描述字,好比操作完打开的文件要调用fclose关闭打开的文件。 |
TCPTCP把连接作为最基本的对象,每一条TCP连接都有两个端点,这种断点我们叫作套接字(socket),它的定义为端口号拼接到IP地址即构成了套接字,例如,若IP地址为192.3.4.16 而端口号为80,那么得到的套接字为192.3.4.16:80。 | |
TCP连接的建立(三次握手) |
|
TCP连接的释放(四次挥手) | |
为什么客户端最后还要等待2MSL? |
MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。 |
如果已经建立了连接,但是客户端突然出现故障了怎么办? | TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。 |
1,tcp分客户端和服务端。2,客户端对应的对象是Socket。服务端对应的对象是ServerSocket。 | |
客户端对应的对象是Socket /* 需求:给服务端发送给一个文本数据。 s.close(); 如果这个建立了就通了,就有了socket 流 tcp 的服务端对应着多个客户端 一个客户端上面有输入和输出,就像是电话上有听筒和话筒,打电话的人是这边的话筒对应着那一面的听筒,那边的话筒对应着这的听筒,在当客户端和服务端建立连接以后,服务端会得到客户端的对象,同样客户端对象都会存在输入和 输出,客户端的输入对应着服务端的客户端对象的输出,客户端的输出对应着服务端的客户端对象的输入。
| 服务端对应的对象是ServerSocket /* */ serverSocket 只能在dos 命令下运行 所以不能在eclipse 中运行 在dos 命令下运行的时候把里面的注释文字删除 把这两个文件拷贝过来
然后服务端就会出现
|
udpDatagramSocket 既能发送又能接收,数据包就是DatagramPacket,建立发送端和接收端,用完socket 要进行关闭,发送端和接收端是 两个独立运行的程序。 由于udp 是面向无连接的 | |
// 表示的是把数据发送到192.168.111.1 这个10000端口上,表示把数据包从8888端口发送到10000端口
//3,通过socket服务,将已有的数据包发送出去。通过send方法。ds.send(dp);//4,关闭资源。ds.close();}} 如果这样直接运行数据就丢失了 | |
//10000表示的接收来自于10000端口的数据 while(true) { //2,定义数据包。用于存储数据。 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); //3,通过服务的receive方法将收到数据存入数据包中。 ds.receive(dp);//阻塞式方法。 //4,通过数据包的方法获取其中的数据。 String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); int port = dp.getPort(); System.out.println(ip+"::"+data+"::"+port); } //5,关闭资源 //ds.close(); } } DatagramSocket 既能发送又能接收,数据包就是DatagramPacket,建立发送端和接收端,用完socket 要进行关闭,发送端和接收端是 两个独立运行的程序。
运行结果: | |
实例一: 操作过程是首先运行udpRece 但是运行这个文件的时候没有什么反应,主要是 ds.receive(dp);//阻塞式方法,就是一直等待发送端有数据了为准,如果没有数据就一直等待,然后运行发送端 加上while(true)的原因就是一直等待发送端发过来的数据,并且接收端取消了资源关闭,就是资源一直是开着的,这样导致的结果就是接收端不用关闭,发送端那边只要改了值直接一运行就可以了
| 实例二: UDP 键盘录入 接收端的代码就是上面的代码,发送端发生了变化,采用的是键盘录入的方式 先运行receive 端 udpsend2 端进行的,回车以后
|
实例三: /* public void run() class ChatDemo 运行一下主函数就启动了两个线程 就是这样一种感觉 其实聊天室就是在同一个界面的,其实道理和开两个窗口是一样的 |