調用 outt.flush ();
2. java socket編程 是什麼協議
Socket,又稱為套接字,Socket是計算機網路通信的基本的技術之一。如今大多數基於網路的軟體,如瀏覽器,即時通訊工具甚至是P2P下載都是基於Socket實現的。本文會介紹一下基於TCP/IP的Socket編程,並且如何寫一個客戶端/伺服器程序。
方法/步驟
Java中的socket編程 下面的部分將通過一些示例講解一下如何使用socket編寫客戶端和伺服器端的程序。 注意:在接下來的示例中,我將使用基於TCP/IP協議的socket編程,因為這個協議遠遠比UDP/IP使用的要廣泛。並且所有的socket相關的類都位於java.net包下,所以在我們進行socket編程時需要引入這個包。
寫入數據 接下來就是寫入請求數據,我們從客戶端的socket對象中得到OutputStream對象,然後寫入數據後。很類似文件IO的處理代碼。
打開伺服器端的socket
讀取數據 通過上面得到的socket對象獲取InputStream對象,然後安裝文件IO一樣讀取數據即可。這里我們將內容列印出來。
使用socket實現一個回聲伺服器,就是伺服器會將客戶端發送過來的數據傳回給客戶端。
3. java編程中,Socket通信是怎麼實現的
java編程對於Socket之間的通信過程如下:
服務端往Socket的輸出流裡面寫東西,客戶端就可以通過Socket的輸入流讀取對應的內容。Socket與Socket之間是雙向連通的,所以客戶端也可以往對應的Socket輸出流裡面寫東西,然後服務端對應的Socket的輸入流就可以讀出對應的內容。下面來看一些服務端與客戶端通信的例子:
publicclassServer{
publicstaticvoidmain(Stringargs[])throwsIOException{
//為了簡單起見,所有的異常信息都往外拋
intport=8899;
//定義一個ServerSocket監聽在埠8899上
ServerSocketserver=newServerSocket(port);
//server嘗試接收其他Socket的連接請求,server的accept方法是阻塞式的
Socketsocket=server.accept();
//跟客戶端建立好連接之後,我們就可以獲取socket的InputStream,並從中讀取客戶端發過來的信息了。
Readerreader=newInputStreamReader(socket.getInputStream());
charchars[]=newchar[64];
intlen;
StringBuildersb=newStringBuilder();
while((len=reader.read(chars))!=-1){
sb.append(newString(chars,0,len));
}
System.out.println("fromclient:"+sb);
reader.close();
socket.close();
server.close();
}
}
客戶端代碼
Java代碼publicclassClient{
publicstaticvoidmain(Stringargs[])throwsException{
//為了簡單起見,所有的異常都直接往外拋
Stringhost="127.0.0.1";//要連接的服務端IP地址
intport=8899;//要連接的服務端對應的監聽埠
//與服務端建立連接
Socketclient=newSocket(host,port);
//建立連接後就可以往服務端寫數據了
Writerwriter=newOutputStreamWriter(client.getOutputStream());
writer.write("HelloServer.");
writer.flush();//寫完後要記得flush
writer.close();
client.close();
}
}
4. 用JAVA編寫一個socket通信程序。
importjava.io.BufferedReader;
importjava.io.InputStreamReader;
importjava.net.ServerSocket;
importjava.net.Socket;
publicclassServer{
publicstaticvoidmain(String[]args){
ServerSocketss;
Sockets;
try{
ss=newServerSocket(8888);
s=ss.accept();
InputStreamReaderisr=newInputStreamReader(s.getInputStream());
BufferedReaderbr=newBufferedReader(isr);
System.out.println(br.readLine());
br.close();
isr.close();
}catch(Exceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
importjava.io.PrintWriter;
importjava.net.Socket;
publicclassClient{
publicstaticvoidmain(String[]args){
try{
Sockets=newSocket("127.0.0.1",8888);
PrintWriterpw=newPrintWriter(s.getOutputStream());
pw.write("helloserver");
pw.flush();
pw.close();
}catch(Exceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
5. 用Java的socket編程實現c/s結構程序
今天太晚了,改天給你做一個,記得提醒我,這個如果只是要個簡單的,我半個小時就搞定了
給我個郵箱
現在給貼出我的代碼: 整個結構分兩個工程
1。服務端工程NioServer.java: 採用nio 方式的非同步socket通信,不僅可以實現你的伺服器還可以讓你多學習一下什麼是nio
2。客戶端工程UserClient.java: 採用Swing技術畫了一個簡單的UI界面,比較土,原因是我沒那麼多時間去設計界面,你需要的話可以自己去修改得漂亮點,相信不難
現在貼工程1:
package com.net;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
public static final int SERVERPORT=5555;
public static final String USERNAME="wangrong";
public static final String PASSWORD="123456";
public static final String ISACK="ACK";
public static final String ISNAK="NAK!";
// Selector selector;//選擇器
// SelectionKey key;//key。 一個key代表一個Selector 在NIO通道上的注冊,類似主鍵;
// //取得這個Key後就可以對Selector在通道上進行操作
private ByteBuffer echoBuffer = ByteBuffer.allocate( 1024 );// 通道數據緩沖區
public NioServer(){
}
public static void main(String[] args) throws IOException {
NioServer ns=new NioServer();
ns.BuildNioServer();
}
public void BuildNioServer() throws IOException{
/////////////////////////////////////////////////////////
///////先對服務端的ServerSocket進行注冊,注冊到Selector ////
/////////////////////////////////////////////////////////
ServerSocketChannel ssc = ServerSocketChannel.open();//新建NIO通道
ssc.configureBlocking( false );//使通道為非阻塞
ServerSocket ss = ssc.socket();//創建基於NIO通道的socket連接
//新建socket通道的埠
ss.bind(new InetSocketAddress("127.0.0.1",SERVERPORT));
Selector selector=Selector.open();//獲取一個選擇器
//將NIO通道選綁定到擇器,當然綁定後分配的主鍵為skey
SelectionKey skey = ssc.register( selector, SelectionKey.OP_ACCEPT );
////////////////////////////////////////////////////////////////////
//// 接收客戶端的連接Socket,並將此Socket也接連注冊到Selector ////
///////////////////////////////////////////////////////////////////
while(true){
int num = selector.select();//獲取通道內是否有選擇器的關心事件
if(num<1){continue; }
Set selectedKeys = selector.selectedKeys();//獲取通道內關心事件的集合
Iterator it = selectedKeys.iterator();
while (it.hasNext()) {//遍歷每個事件
try{
SelectionKey key = (SelectionKey)it.next();
//有一個新聯接接入事件,服務端事件
if ((key.readyOps() & SelectionKey.OP_ACCEPT)
== SelectionKey.OP_ACCEPT) {
// 接收這個新連接
ServerSocketChannel serverChanel = (ServerSocketChannel)key.channel();
//從serverSocketChannel中創建出與客戶端的連接socketChannel
SocketChannel sc = serverChanel.accept();
sc.configureBlocking( false );
// Add the new connection to the selector
// 把新連接注冊到選擇器
SelectionKey newKey = sc.register( selector,
SelectionKey.OP_READ );
it.remove();
System.out.println( "Got connection from "+sc );
}else
//讀客戶端數據的事件,此時有客戶端發數據過來,客戶端事件
if((key.readyOps() & SelectionKey.OP_READ)
== SelectionKey.OP_READ){
// 讀取數據
SocketChannel sc = (SocketChannel)key.channel();
int bytesEchoed = 0;
while((bytesEchoed = sc.read(echoBuffer))> 0){
System.out.println("bytesEchoed:"+bytesEchoed);
}
echoBuffer.flip();
System.out.println("limet:"+echoBuffer.limit());
byte [] content = new byte[echoBuffer.limit()];
echoBuffer.get(content);
String result=new String(content);
doPost(result,sc);
echoBuffer.clear();
it.remove();
}
}catch(Exception e){}
}
}
}
public void doPost(String str,SocketChannel sc){
boolean isok=false;
int index=str.indexOf('|');
if(index>0){
String name=str.substring(0,index);
String pswd=str.substring(index+1);
if(pswd==null){pswd="";}
if(name!=null){
if(name.equals(USERNAME)
&& pswd.equals(PASSWORD)
){
isok=true;
}else{
isok=false;
}
}else{
isok=false;
}
}else{
isok=false;
}
String result="";
if(isok){
result="ACK";
}else{
result="NAK!";
}
ByteBuffer bb = ByteBuffer.allocate( result.length() );
bb.put(result.getBytes());
bb.flip();
try {
sc.write(bb);
} catch (IOException e) {
e.printStackTrace();
}
bb.clear();
}
}
下面貼工程2
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
public class UserClient implements ActionListener{
JFrame jf;
JPanel jp;
JLabel label_name;
JLabel label_pswd;
JTextField userName;
JButton jb;
JPasswordField paswrd;
JLabel hintStr;
public UserClient (){
jf=new JFrame("XXX 登陸系統");
jp=new JPanel();
jf.setContentPane(jp);
jf.setPreferredSize(new Dimension(350,220));
jp.setPreferredSize(new Dimension(350,220));
jp.setBackground(Color.gray);
label_name=new JLabel();
label_name.setPreferredSize(new Dimension(150,30));
label_name.setText("請輸入帳戶(數字或英文):");
userName=new JTextField();
userName.setPreferredSize(new Dimension(150,30));
jp.add(label_name);
jp.add(userName);
label_pswd=new JLabel();
label_pswd.setPreferredSize(new Dimension(150,30));
label_pswd.setText("請輸入密碼:");
jp.add(label_pswd);
paswrd=new JPasswordField();
paswrd.setPreferredSize(new Dimension(150,30));
jp.add(paswrd);
jb=new JButton("OK");
jb.setPreferredSize(new Dimension(150,30));
jb.setText("確 定");
jb.addActionListener( this);
jp.add(jb);
hintStr=new JLabel();
hintStr.setPreferredSize(new Dimension(210,40));
hintStr.setText("");
hintStr.setForeground(Color.RED);
jp.add(hintStr);
jf.pack();
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private String name;
private String pswd;
public void actionPerformed(ActionEvent e) {
name=userName.getText().trim();
pswd=new String(paswrd.getPassword());
if(pswd==null){
pswd="";
}else{
pswd=pswd.trim();
}
if(name!=null && name.length()>0){
hintStr.setText("正在驗證客戶端,請稍候...");
start();
}
}
OutputStream os;
Socket s;
InputStream is;
public void start(){
//建立聯網線程
new Thread(new Runnable(){
public void run() {
try {
s=new Socket("127.0.0.1",5555);
//寫
os=s.getOutputStream();
os.write(name.getBytes());
os.write('|');//用戶名與密碼用"|"分隔
os.write(pswd.getBytes());
os.flush();
//讀內容
Thread.sleep(1000);
is=s.getInputStream();
int len=is.available();
System.out.println("len:"+len);
byte[] bytes=new byte[len];
is.read(bytes);
String resut=new String(bytes);
System.out.println("resut:"+resut);
//TODO 這里通過返回結果處理
if(resut.equals("ACK")){
hintStr.setText("驗證成功,歡迎光臨!");
}else{
paswrd.setText(null);
hintStr.setText("用戶名或密碼錯誤,請重新輸入");
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
// try {
// os.close();
// is.close();
// s.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}
}).start();
}
public static void main(String[] args) {
new UserClient();
}
}
6. java 非同步編程
用非同步輸入輸出流編寫Socket進程通信程序
在Merlin中加入了用於實現非同步輸入輸出機制的應用程序介麵包:java.nio(新的輸入輸出包,定義了很多基本類型緩沖(Buffer)),java.nio.channels(通道及選擇器等,用於非同步輸入輸出),java.nio.charset(字元的編碼解碼)。通道(Channel)首先在選擇器(Selector)中注冊自己感興趣的事件,當相應的事件發生時,選擇器便通過選擇鍵(SelectionKey)通知已注冊的通道。然後通道將需要處理的信息,通過緩沖(Buffer)打包,編碼/解碼,完成輸入輸出控制。
通道介紹:
這里主要介紹ServerSocketChannel和 SocketChannel.它們都是可選擇的(selectable)通道,分別可以工作在同步和非同步兩種方式下(注意,這里的可選擇不是指可以選擇兩種工作方式,而是指可以有選擇的注冊自己感興趣的事件)。可以用channel.configureBlocking(Boolean )來設置其工作方式。與以前版本的API相比較,ServerSocketChannel就相當於ServerSocket(ServerSocketChannel封裝了ServerSocket),而SocketChannel就相當於Socket(SocketChannel封裝了Socket)。當通道工作在同步方式時,編程方法與以前的基本相似,這里主要介紹非同步工作方式。
所謂非同步輸入輸出機制,是指在進行輸入輸出處理時,不必等到輸入輸出處理完畢才返回。所以非同步的同義語是非阻塞(None Blocking)。在伺服器端,ServerSocketChannel通過靜態函數open()返回一個實例serverChl。然後該通道調用serverChl.socket().bind()綁定到伺服器某埠,並調用register(Selector sel, SelectionKey.OP_ACCEPT)注冊OP_ACCEPT事件到一個選擇器中(ServerSocketChannel只可以注冊OP_ACCEPT事件)。當有客戶請求連接時,選擇器就會通知該通道有客戶連接請求,就可以進行相應的輸入輸出控制了;在客戶端,clientChl實例注冊自己感興趣的事件後(可以是OP_CONNECT,OP_READ,OP_WRITE的組合),調用clientChl.connect(InetSocketAddress )連接伺服器然後進行相應處理。注意,這里的連接是非同步的,即會立即返回而繼續執行後面的代碼。
選擇器和選擇鍵介紹:
選擇器(Selector)的作用是:將通道感興趣的事件放入隊列中,而不是馬上提交給應用程序,等已注冊的通道自己來請求處理這些事件。換句話說,就是選擇器將會隨時報告已經准備好了的通道,而且是按照先進先出的順序。那麼,選擇器是通過什麼來報告的呢?選擇鍵(SelectionKey)。選擇鍵的作用就是表明哪個通道已經做好了准備,准備干什麼。你也許馬上會想到,那一定是已注冊的通道感興趣的事件。不錯,例如對於伺服器端serverChl來說,可以調用key.isAcceptable()來通知serverChl有客戶端連接請求。相應的函數還有:SelectionKey.isReadable(),SelectionKey.isWritable()。一般的,在一個循環中輪詢感興趣的事件(具體可參照下面的代碼)。如果選擇器中尚無通道已注冊事件發生,調用Selector.select()將阻塞,直到有事件發生為止。另外,可以調用selectNow()或者select(long timeout)。前者立即返回,沒有事件時返回0值;後者等待timeout時間後返回。一個選擇器最多可以同時被63個通道一起注冊使用。
應用實例:
下面是用非同步輸入輸出機制實現的客戶/伺服器實常式序――程序清單1(限於篇幅,只給出了伺服器端實現,讀者可以參照著實現客戶端代碼):
程序類圖
public class NBlockingServer {
int port = 8000;
int BUFFERSIZE = 1024;
Selector selector = null;
ServerSocketChannel serverChannel = null;
HashMap clientChannelMap = null;//用來存放每一個客戶連接對應的套接字和通道
public NBlockingServer( int port ) {
this.clientChannelMap = new HashMap();
this.port = port;
}
public void initialize() throws IOException {
//初始化,分別實例化一個選擇器,一個伺服器端可選擇通道
this.selector = Selector.open();
this.serverChannel = ServerSocketChannel.open();
this.serverChannel.configureBlocking(false);
InetAddress localhost = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(localhost, this.port );
this.serverChannel.socket().bind(isa);//將該套接字綁定到伺服器某一可用埠
}
//結束時釋放資源
public void finalize() throws IOException {
this.serverChannel.close();
this.selector.close();
}
//將讀入位元組緩沖的信息解碼
public String decode( ByteBuffer byteBuffer ) throws
CharacterCodingException {
Charset charset = Charset.forName( "ISO-8859-1" );
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode( byteBuffer );
String result = charBuffer.toString();
return result;
}
//監聽埠,當通道准備好時進行相應操作
public void portListening() throws IOException, InterruptedException {
//伺服器端通道注冊OP_ACCEPT事件
SelectionKey acceptKey =this.serverChannel.register( this.selector,
SelectionKey.OP_ACCEPT );
//當有已注冊的事件發生時,select()返回值將大於0
while (acceptKey.selector().select() > 0 ) {
System.out.println("event happened");
//取得所有已經准備好的所有選擇鍵
Set readyKeys = this.selector.selectedKeys();
//使用迭代器對選擇鍵進行輪詢
Iterator i = readyKeys.iterator();
while (i
else if ( key.isReadable() ) {//如果是通道讀准備好事件
System.out.println("Readable");
//取得選擇鍵對應的通道和套接字
SelectableChannel nextReady =
(SelectableChannel) key.channel();
Socket socket = (Socket) key.attachment();
//處理該事件,處理方法已封裝在類ClientChInstance中
this.readFromChannel( socket.getChannel(),
(ClientChInstance)
this.clientChannelMap.get( socket ) );
}
else if ( key.isWritable() ) {//如果是通道寫准備好事件
System.out.println("writeable");
//取得套接字後處理,方法同上
Socket socket = (Socket) key.attachment();
SocketChannel channel = (SocketChannel)
socket.getChannel();
this.writeToChannel( channel,"This is from server!");
}
}
}
}
//對通道的寫操作
public void writeToChannel( SocketChannel channel, String message )
throws IOException {
ByteBuffer buf = ByteBuffer.wrap( message.getBytes() );
int nbytes = channel.write( buf );
}
//對通道的讀操作
public void readFromChannel( SocketChannel channel, ClientChInstance clientInstance )
throws IOException, InterruptedException {
ByteBuffer byteBuffer = ByteBuffer.allocate( BUFFERSIZE );
int nbytes = channel.read( byteBuffer );
byteBuffer.flip();
String result = this.decode( byteBuffer );
//當客戶端發出」@exit」退出命令時,關閉其通道
if ( result.indexOf( "@exit" ) >= 0 ) {
channel.close();
}
else {
clientInstance.append( result.toString() );
//讀入一行完畢,執行相應操作
if ( result.indexOf( "\n" ) >= 0 ){
System.out.println("client input"+result);
clientInstance.execute();
}
}
}
//該類封裝了怎樣對客戶端的通道進行操作,具體實現可以通過重載execute()方法
public class ClientChInstance {
SocketChannel channel;
StringBuffer buffer=new StringBuffer();
public ClientChInstance( SocketChannel channel ) {
this.channel = channel;
}
public void execute() throws IOException {
String message = "This is response after reading from channel!";
writeToChannel( this.channel, message );
buffer = new StringBuffer();
}
//當一行沒有結束時,將當前字竄置於緩沖尾
public void append( String values ) {
buffer.append( values );
}
}
//主程序
public static void main( String[] args ) {
NBlockingServer nbServer = new NBlockingServer(8000);
try {
nbServer.initialize();
} catch ( Exception e ) {
e.printStackTrace();
System.exit( -1 );
}
try {
nbServer.portListening();
}
catch ( Exception e ) {
e.printStackTrace();
}
}
}
程序清單1
小結:
從以上程序段可以看出,伺服器端沒有引入多餘線程就完成了多客戶的客戶/伺服器模式。該程序中使用了回調模式(CALLBACK)。需要注意的是,請不要將原來的輸入輸出包與新加入的輸入輸出包混用,因為出於一些原因的考慮,這兩個包並不兼容。即使用通道時請使用緩沖完成輸入輸出控制。該程序在Windows2000,J2SE1.4下,用telnet測試成功。
7. 關於JAVA socket編程
先運行伺服器端類,然後再運行客戶端類,就可以了
/**
*伺服器端類
*/
public class Server {
public static void main(String[] args) throws IOException{
Server server = new Server();
server.start();
}
public void start() throws IOException{
//ServerSocket 對當前伺服器的服務埠的綁定
//這個埠號不能重復綁定,不能同時執行兩邊
ServerSocket ss = new ServerSocket(8888);
while(true){
//accept 開始等待(IO Block)客戶連接(啟動監聽),如果沒有客戶端連接,一直掛起等待下去。
//如果有客戶端連接,才會繼續執行下去,返回的Socket實例s 代表對於客戶端連接。
Socket s = ss.accept();
//創建並啟動客戶服務線程,為客戶服務
//當前線程再次返回到accept等待,下一個客戶連接
new Service(s).start();//創建線程
}
}
class Service extends Thread{
Socket s;
public Service(Socket s){
this.s = s;
}
public void run(){
try{
//s代表客戶端
//s 中的in代表從客戶傳遞過來的流
//s 中的out代表從伺服器到客戶端傳輸流
InputStream in = s.getInputStream();
Scanner sc = new Scanner(in);//System.in是操作系統後台
OutputStream out = s.getOutputStream();
//out.write("您好!您需要點啥?\n".getBytes("GBK"));
//out.flush();//清理緩沖,確保發送到客戶端
while(true){
String str = sc.nextLine();//IO Block
if(str.equals("連接伺服器")){
out.write("連接成功!\n".getBytes("GBK"));
out.flush();
break;
}
}
}catch(IOException e){
e.printStackTrace();
}
}
}
}
/**
*客戶端類
*/
public class Client {
public static void main(String[] args) throws IOException{
// new Socket() 連接到指定的伺服器埠,當前用的是本機的埠
Socket s = new Socket("localhost", 8888);
//返回s代表連接到了伺服器
//s代表對伺服器的連接
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
out.write("連接伺服器\n".getBytes("gbk"));
out.flush(); //清理緩沖,確保發送到服務端
Scanner sc = new Scanner(in);
String str = sc.nextLine();
System.out.println(str); //把從伺服器返回的信息,列印到控制台。
out.flush();
}
}
8. 關於java Socket的非同步調用,思路問題,100元現金報酬
這樣不就好了,不管伺服器還是客戶端,只要socket連接成功,就分別開啟一個讀線程,不停讀取另一端數據,再開啟一個寫線程,比如從控制端讀取的消息。在發送到另一端。
9. java socket編程,我要建立一個socket伺服器,要接收5000個客戶端的訪問,並且還要接收處理客戶端的數據
應該能用線程池解決。 貌似當線程數滿的時候,就會等待現有線程的釋放。
10. JAVA和其他語言非同步SOCKET的問題
你需要補充自己的答案:你遠程管理伺服器可以在不重新啟動它嗎?您ulimit-a命令,當您每次啟動tomcat,把打開的文??件的最大數量值設置為
的/ proc / sys目錄/ FS /文件放到tomcat的啟動腳本最大限制的總的系統,在sysctl.conf中決定。
獲得的價值的ulimit當前用戶打開的文件(包括套接字連接)允許的最大數量
使用ulimit-n命令目前只用於當前登錄的後的值用戶有效的系統重新啟動或用戶出口將失敗。
如果你需要一個永久的,可以在/ etc / security / limits.conf中
格式說明符這個文件中的參數更詳細的,如果你想設置為4096,您可以添加以下內容:
*軟NOFILE 4096
*硬碟NOFILE 4096
如果你使用Linux的RedHat8的或9,在/ etc / pam.d / login文件登錄文件中添加以下行
會議要求/ lib / security中/是pam_limits.so
或
會議要求在pam_limits.so