iOS 开发基础(6)--网络通信
OSI 的七层协议体系结构的概念清晰,理论完整,当时它既复杂又不实用; TCP/IP 体系结构则不同,但是它现在却得到了非常广泛的应用,不过从实质上讲, TCP/IP 只是最上面的三层,因为最下面的网络接口层并没有什么具体内容;因此在学习计算机网络的时候往往采取折中的方法,即综合 OSI 和 TCP/IP 的优点,采用一种只有五层协议的体系结构;
iOS 开发中的网络通信主要是在传输层和应用层进行一些网络 IP 地址,端口以及协议的一些处理;首先是网络层的两种传输协议 UDP 和 TCP 的含义以及区别:
用户数据包协议;UDP 在传输数据之前不需要先建立连接远地主机的运输层在收到 UDP 报文后,不需要给出任何确认;
主要特点:
传输控制协议; TCP 提供面向连接的服务;在传输数据之前必须先建立连接,数据传输完成后要释放连接;建立连接需要通过三次握手,而释放连接需要四次握手;
主要特点:
第一次握手:客户端发送syn包(seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
这个问题的本质就是信道不可靠,但是通信双方需要中间传输的数据是可靠的,而要解决这个问题,无论你是在信息中包含什么信息,三次通信是理论上的最小值,所以三次握手不是TCP本身的要求,而是为了满足在不可靠信道上可靠的传输信息这一需求所致的;这里的本质需求就是,信道不可靠,数据传输要可靠,三次握手之后你先继续握手还是发数据也好,跟进行可靠信息传输的需求就没关系了,因此如果信道可靠,无论什么时候发出消息,对方一定能收到,或者你不关心是否要保证对方收到你的消息,那就能像UDP那样直接发送消息就可以;
1当主机A确认发送完数据且知道B已经接受完了,想要关闭发送数据接口(当然确认信号还是可以发),就会发FIN给主机B;
2主机B收到A发送的FIN,表示收到了,就会发送ACK回复;
3但是这时B可能还在发送数据,没有想要关闭数据口的意思,所以FIN和ACK不是同时发送的,而是等到B数据发送完,才会发送FIN给主机A;
4A收到B发来的FIN,知道B的数据也发送完了,回复ACK,A等待2MSL以后,没有收到B传来的任何消息,知道B已经收到自己的ACK了,A就关闭链接,B也关闭链接;
在客户端发送最后的ACK回复,但是该ACK可能丢失。服务端如果没有收到ACK,将不断重复发送FIN片段。所以客户端不能立即关闭,它必须确认服务端接收到了该ACK,客户端会在发送出ACK之后进入到TIME_WAIT状态,客户端会设置一个计时器,等待2MSL的时间,如果在该时间内再次收到FIN,那么客户端会重发ACK并再次等待2MSL;所谓2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果知道2MSL,客户端都没有再次收到FIN,那么客户端推断ACK已经成功接收,则结束TCP连接;
HTTP是一种无状态的连接,客户端每次读取web网页时,服务器都会认为这是一次新的会话。但有时候我们需要持久保存一些用户信息,比如登录时的用户名和密码等;而这些信息都是需要Cookie和Session来保存;
这两个的本质区别就是Cookie是保存在客户端的,而Session是保存在服务器上的;
当服务器接收到 cookie 后,会根据 cookie 中的 SessionID 来找到这个客户的 session。如果没有,则会生成一个新的 SessionID 发送给客户端。
HTTP 连接使用的是"请求--响应"的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据;一次请求后立即断开;HTTP 使用的的面向连接的 TCP 作为传输层协议,保证了数据的可靠性;但是 HTTP属于无状态,无连接;虽然使用了 TCP 连接,但通信的双方不需要先建立连接;
socket 连接通常情况下就是 TCP 连接,因此 socket 连接一旦建立,通信双方即可开始互相发送数据内容,直到双方的连接断开;但在实际应用中,客户端和服务器之间的通行防火墙会关闭长时间处于非活跃状态的连接而导致 socket 连接中断,因此需要通过轮询告诉网络该连接处于活跃状态;
连接过程分为三个步骤:服务器监听,客户端请求,连接确认;
服务器监听 :服务器端套接字并不定位具体的客户端套接字,而是处于等待连接状态,实时监测网络状态,等待客户端的连接请求;
客户端的连接请求 :指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字,为此客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端的套接字的地址和端口号,然后就向服务器端套接字提出连接请求;
连接确认 :当服务器端套接字监听到或者说收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接,而服务器端的套接字继续处于监听状态,继续接受其它客户端套接字的连接请求;
HTTP的 URL 的一般形式是: http://<主机>:<端口>/<路径>
HTTP 的默认端口号是:80;
HTTP 有两类报文:
1请求报文---从客户端向服务器发送的请求报文
2响应报文---从服务器到客户的回答
特点:所有的请求参数都拼接都 URL 的后面;
缺点:
特点:
1xx 保留响应保留;
2xx 请求成功接收;
3xx 为完成请求客户端需要进一步细化请求;
4xx 客户端请求错误(参数,方式不正确);
5xx 服务器端有错误;
ServerSocket的构造方法
ServerSocket()创建非绑定服务器套接字。
ServerSocket(int port)
创建绑定到特定端口的服务器套接字。
ServerSocket(int port,
int backlog) 利用指定的 backlog
创建服务器套接字并将其绑定到指定的本地端口号。
ServerSocket(int port,
int backlog, InetAddress bindAddr)
使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
如果你的电脑有多块网卡 那么就可以指定本地IP中的一个
如果你是单网卡, 那么就无需指定
代码
import javaioIOException;import javanetServerSocket;
public class Demo {
private static ServerSocket serverSocket;
public static void main(String[] args)throws IOException {
serverSocket = new ServerSocket(8880);
Systemoutprintln(serverSockettoString());
//String toString() 作为 String 返回此套接字的实现地址和实现端口。
}
}
输出
ServerSocket[addr=0000/0000,localport=8880]也就是说没有指定本地其他Ip的时候, 服务器会把此端口绑定到0000上面
1首先,了解socket的连接过程:
1)服务器监听;2)客户端请求;3)连接确认(具体详情可以见,我在这也就不多说了)。
2socket通信机制:
服务器端
一、创建服务器套接字(CREATE)。
二、服务器套接字进行信息绑定(BIND),并开始监听连接(LISTEN)。
三、接受来自客户端的连接请求(ACCEPT),并创建接收进程。
四、开始数据传输(SEND、RECEIVE)。
五、关闭套接字(CLOSESOCKET)。
客户机端
一、创建客户机套接字(CREATE)。
二、与远程服务器进行连接(CONNECT),如被接受则创建接收进程。
三、开始数据传输(SEND、RECEIVE)。
四、关闭套接字(CLOSESOCKET)。
具体在Java中的实现是:
服务器端:
1)创建ServerSocket,需要使用端口号进行标识,以便客户端进行连接。
如:ServerSocket serverSocket = new ServerSocket(9999);
2)创建Socket获取连接
如: Socket socket = serverSocketaccept();
3)便可以进行通信内容传输了。
客户端:
1)创建Socket,进行与服务器连接,需要填写服务器ip,以及服务器的端口号
如:Socket socket = new Socket("127001", 9999);
2)进行通信内容的传输。
以上只是一个简单的socket通信案例,想要了解的可以进入该链接下载:http://downloadcsdnNET/detail/xia09222826/8244423
3利用socket通信进行服务器端到客户端的消息推送的思路:
客户端登录后发送一个消息给服务器端,用一个标识作为用户客户端程序关闭后服务器端是否推送消息给客户端,如果有则进行消息推送,如果没有则不进行消息推送,而当程序运行时就是一般的socket通信,也就是服务器端写一条消息推送给客户端,客户端便可以接收,并在消息栏上显示,点击消息栏进行相应的界面即可。
服务器就不多说了,方法是差不多的。
客户端:
需要使用Service来进行监听:
[java] view plain copy
public class PushService extends Service {
private PushClient mClient;
private Handler mHandler;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
superonCreate();
initHandler();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mClient = new PushClient(new InetSocketAddress("1921684101", 9999),
mHandler);
mClientstart();
return superonStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
if (mClient != null) {
mClientdisConnect();
}
superonDestroy();
}
/
初始化Handler
/
private void initHandler() {
mHandler = new Handler(new Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msgwhat) {
case ConstPUSH_MSG:
String pushMsg = msgobjtoString();
showNotification(pushMsg);
break;
default:
break;
}
return false;
}
});
}
/
在状态栏显示通知
/
@SuppressWarnings("deprecation")
private void showNotification(String msg) {
// 创建一个NotificationManager的引用
NotificationManager notificationManager = (NotificationManager) getSystemService(androidcontentContextNOTIFICATION_SERVICE);
// 定义Notification的各种属性
Notification notification = new Notification(Rdrawableic_launcher,
msg, SystemcurrentTimeMillis());
// FLAG_AUTO_CANCEL 该通知能被状态栏的清除按钮给清除掉
// FLAG_NO_CLEAR 该通知不能被状态栏的清除按钮给清除掉
// FLAG_ONGOING_EVENT 通知放置在正在运行
// FLAG_INSISTENT 是否一直进行,比如音乐一直播放,知道用户响应
notificationflags |= NotificationFLAG_AUTO_CANCEL; // 表明在点击了通知栏中的"清除通知"后,此通知不清除,经常与FLAG_ONGOING_EVENT一起使用
// DEFAULT_ALL 使用所有默认值,比如声音,震动,闪屏等等
// DEFAULT_LIGHTS 使用默认闪光提示
// DEFAULT_SOUND 使用默认提示声音
// DEFAULT_VIBRATE 使用默认手机震动,需加上<uses-permission
// android:name="androidpermissionVIBRATE" />权限
notificationdefaults = NotificationDEFAULT_SOUND;
// 设置通知的事件消息
CharSequence contentTitle = msg; // 通知栏标题
CharSequence contentText = msg; // 通知栏内容
Intent notificationIntent = new Intent(this, TestActivityclass); // 点击该通知后要跳转的Activity
PendingIntent contentItent = PendingIntentgetActivity(this, 0,
notificationIntent, 0);
notificationsetLatestEventInfo(this, contentTitle, contentText,
contentItent);
// 把Notification传递给NotificationManager
notificationManagernotify(0, notification);
}
这样就可以在将接收到的消息在消息栏上显示了,点击后便可以进入相应的界面了。
正确的端口号,可以在域名后面输入“端口号”就可以访问了。
例如:端口号,只用在后边加上“/:204××”就可以了。
TCP与UDP段结构中端口地址都是16比特,可以有在0-65535范围内的端口号。任何TCP/IP实现所提供的服务都用1-1023之间的端口号,是由ICANN来管理的。端口号从1024-49151是被注册的端口号,被IANA指定为特殊服务使用。从49152-65535是动态或私有端口号。
扩展资料:
各个端口及端口号的实际用途
1、1系端口
POP3服务器开放102端口,用于接收邮件,客户端访问服务器端的邮件服务;NEWS新闻组传输协议,承载USENET通信。这个端口的连接通常是人们在寻找USENET服务器;137、138是UDP端口,当通过网上邻居传输文件时用这个端口。
2、2系端口
FTP服务器开放的21端口,用于上传、下载。最常见的攻击者用于寻找打开anonymous的FTP服务器的方法。这些服务器带有可读写的目录;PcAnywhere建立的TCP和22端口的连接可能是为了寻找ssh;扫描23端口是为了找到机器运行的操作系统。
0条评论