TCP网络编程之使用序列化和多线程实现简单的多并发

1,049 阅读6分钟

一、需求内容: TCP实现并发访问 这篇文章主要讲如何使用TCP实现一个简单的多并发,也就是说需要实现多个客户端可以同时访问服务端,而且服务端可以及时作出响应,并返回数据到用户.

具体内容就是写一个登陆验证,实现多个用户同时登陆服务端时,服务端可以在有用户访问时可以同时接收其它用户的请求,也就是并发.对用户输入的用户名和密码进行验证后返回给客户端登陆结果.

二、需求分析 根据要求需要实现多个用户的登陆验证,那么就需要实现多线程来保证每个客户端都可以单独访问服务端,而且服务端可以在线程空置的情况下去处理其他客户端的请求.这样就可以实现并发了. 多线程的具体实现就是单独写一个登录的线程,每次客户端访问服务端的时候,服务端都会创建一个新的线程,把获得的服务端Socket对象传到线程当中去,让登录线程去处理请求. 这时服务端相当于是一个接待客户的角色,具体实现客户的需求交给线程去做.

需要注意的是,多个用户登录的账户名和密码都是不同的,也就是我们不能使用实现Runnable接口的方法创建登录线程,因为这种方法会共享属性,而需要使用继承Thread类来创建登录线程.

根据要求每个登录的用户我们可以把它看做一个对象,我们可以把它的账户名和密码序列化为用户对象,然后客户端把这个对象传给服务端,服务端进行反序列化获得属性值后即可验证客户端的账户名密码是否正确.

所以我们还要建一个User用户类,并且让其实现Serializable接口,设置它的序列化ID,这样就可以将它封装为对象传输了.

2.实现流程 (1)定义用户类 根据前边的需求分析,我们需要定义一个可以实现序列化的用户类,这样每次有客户端进行登录验证时,我们都可以将登录信息包装为一个对象,然后传输给服务端进行验证. 定义用户名和登录密码,将其封装.

当中要点就是实现Serializable接口,因为这是它能包装为对象的前提,然后每次实现这个接口都不要忘记设置它的序列化ID,否则运行时容易出现序列化对象时匹配错误的情况,序列化ID是一个序列化类的唯一标识,在客户端进行序列化将属性包装为对象时,系统会根据这个序列化ID来找它包装对象的目标类.

所以千万不要忘记设置序列化ID,具体我之前写的序列化和反序列化文章有写过如何配置序列化ID.

(2)客户端代码编写 这里我将定义Socket等对象的代码放在try{ }上头,我将主要代码放到如下:

客户端和之前讲的TCP网络通信一样,先创建Socket对象,指定IP地址及端口号;然后使用getOutputStream()方法来获取字节输出流对象,然后创建ObjectOutputStream对象用于序列化,构造对象时传入OutputStream对象;

之后使用扫描器来输入用户名和密码,将用户名和密码传入新建的User类对象,这样就成功构造了一个User对象,最后使用ObjectOutputStream的writeObject(Object object)方法将对象输出到服务端.

从服务端获取返回消息和之前的TCP网络通信一样,使用getInputStream()方法获取字节流对象,即可使用read()方法读取后,将字节数组转为字符串打印了.

(3)服务端代码编写:

这里我将服务端的代码展示如下,其中catch{ }和finally{ }模块我没放上来,模块中无非就是抓取到的异常以及关闭流的操作,这些同学们可以看我之前的讲IO流的文章有讲到如何关闭流,简单说就是先开后关,最先开启的流最后关.

IO流中我们判断一个流是否开启是通过看read()方法和write()方法,这里面有ServerSocket开启的流和Socket开启的流需要注意一下.

然后具体内容就是创建服务端SErverSocket对象,然后再while循环中使用Socket对象来接收客户端发来的消息.然后new一个登陆线程,传入socket对象进去.开启线程即可

(4)登录线程编写 登录线程别忘记声明Socket 属性,因为这样可以使用构造方法来进行传入服务端的Socket对象(也就是获取到的客户端对象),这样就可以对客户端的请求进行处理了;

创建LoginThread登录线程后,还需要重写其中的run()方法,在run()方法中对客户端请求进行处理.

首先通过Socket类的getInputStyream()方法获取字节输入流对象; 然后创建序列化输入流对象ois,通过new ObjectInputStyream(InputStream in)方法创建; 之后使用readObject()读取Object对象并将其强转为User类对象;

最后使用Socket类的getOutputStream()方法来获得字节输出流对象,应用它来回复客户端用户名密码的验证情况.

总结

其实简单并发的实现并不难,只要掌握几个要点即可:

(1) 定义用户类时使用序列化,也就是实现Serilizable()接口,然后设置序列化对象(通过Idea设置后,在Class类名处点黄色警告线下的内容,或者alt+enter实现);

(2)服务端使用多线程,每次有客户端请求时,创建一个线程让线程去处理,这里别忘记将客户端Socket对象传到线程中去,这样线程才可以获取客户端发来的数据.

(3)创建多线程类用于处理服务端传过来的任务,也就是对客户端传来的数据进行处理并回复; 这里使用的线程类需要extends Thread类,因为这样创建的线程不共享属性,可以分别不同客户端传输过来的信息. 并且需要重写Thread类的run方法,在方法内部处理客户端的请求.

创作不易,请小伙伴们多点点关注,博主会很开心的给您比心哟!!