【java的socket编程】结合多线程Thread实现通信(使用线程池和非线程池对比)、java开发UDP/IP网络程序


首先:accept()和Read()方法都有阻塞特性

结合多线程实现socket

在Socket技术中,常用的实践方式就是Socket结合Thread多线程技术,客户端每发起一次新的请求,就把这个请求交给新创建的线程来执行这次业务。当然,如果使用线程池技术,则会更加高效。本示例先使用原始的非线程池来进行演示。

//socket类提供了两个方法用于得到输入流和输出流,分别是getInputStream()和getOutputStream() 可以对其进行包装
//例如:Socket socket = new Socket(“localhost”,8189);
// PrintStream oStream = new PrintStream( new BufferedOutputStream(socket.getOutputStream()));
//DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
一个使用DataInputStream的简单例子:

 public static void main(String [] args)
   {
      String serverName = args[0];
      int port = Integer.parseInt(args[1]);
      try
      {
         System.out.println("连接到主机:" + serverName + " ,端口号:" + port);
         Socket client = new Socket(serverName, port);
         System.out.println("远程主机地址:" + client.getRemoteSocketAddress());
         OutputStream outToServer = client.getOutputStream();
         DataOutputStream out = new DataOutputStream(outToServer);
 
         out.writeUTF("Hello from " + client.getLocalSocketAddress());
         InputStream inFromServer = client.getInputStream();
         DataInputStream in = new DataInputStream(inFromServer);
         System.out.println("服务器响应: " + in.readUTF());
         client.close();
      }catch(IOException e)
      {
         e.printStackTrace();
      }
   }

使用非线程池(拓展Thread)

beginthread:


//多线程实现socket
public class BeginThread extends Thread{


    private Socket socket;
    public BeginThread(Socket socket)
    {
        super();
        this.socket = socket;
    }
    @Override
    public void run(){
        try{
            InputStream inputStream = socket.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            char[] charArr = new char[1000];
            int readLen = -1;
            while((readLen = (inputStreamReader.read(charArr))) != -1)
            {
                String newString = new String(charArr,0,readLen);
                System.out.println(newString);
            }

            inputStreamReader.close();
            inputStream.close();//关闭两个流
            socket.close();//关闭socket
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

beginserver类:


public class BeginServer {

    public static void main(String[]args) throws IOException {
        ServerSocket socket = new ServerSocket(8888);
        int runTag = 1;
        while (runTag == 1)
        {
            Socket socket1 = socket.accept();
            BeginThread beginThread = new BeginThread(socket1);
            beginThread.start();
        }

        socket.close();

    }
}

BeginClient :


public class BeginClient {

    public static void main(String[]args) throws IOException {
        Socket socket = new Socket("localhost",8888);
        OutputStream outputStream = socket.getOutputStream();
//        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
//        outputStreamWriter.write(String.valueOf("我是中国人".getBytes(StandardCharsets.UTF_8)));
        outputStream.write("我是中国人yaoo".getBytes(StandardCharsets.UTF_8));
        outputStream.close();
        socket.close();
    }
}

客户端每次发完一条数据就会关闭连接,而服务端一直会有线程接收请求。修改客户端的字符串,服务端结果:
在这里插入图片描述
由于 Socket socket1 = socket.accept();的阻塞特性,只有服务端受到客户端的信号之后才会开启一个新的线程。

使用线程池(Executor pool)

将以上代码修改为使用线程池:
beginThread只需要修改为
implements Runnable
而beginServer改为:


public class BeginServer {
private ServerSocket serverSocket;
private Executor pool;
public BeginServer(int port,int poolSize)
{
    try{
        serverSocket = new ServerSocket(port);
        pool = Executors.newFixedThreadPool(poolSize);

    }catch (IOException e)
    {
        e.printStackTrace();
    }
}

public void startServer() {
    try {
        while (true) {
            Socket socket = serverSocket.accept();
            pool.execute(new BeginThread(socket));
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
    public static void main(String[]args) throws IOException {
       BeginServer beginServer = new BeginServer(8888,10000);
        beginServer.startServer();
    }
}

在这里插入图片描述
结果是一样的。

使用DatagramPacket DatagramSocket开发UDP/IP程序

DatagramPacket DatagramSocket是用来支持数据报通信的两个类,前者由于表示数据报,后者用于建立通信连接
写改程序首先需要建立一个DatagramSocket对象,用来接收或者发送数据报,然后以DatagramPacket 作为数据传输的载体。

使用UDP获取服务端时间

client:


public class UdpClient {
    public void go() throws IOException, UnknownHostException{
        DatagramPacket ingramPacket;
        DatagramPacket outgramPacket;
        DatagramSocket datagramSocket;
        InetAddress serverAdress;
        byte[]msg = new byte[100];//缓冲区
        String receivedmsg;
        datagramSocket = new DatagramSocket();
        System.out.println("an udpclient ,datagramsocket:"+datagramSocket.getPort()+"localport:"+datagramSocket.getLocalPort());
        serverAdress = InetAddress.getLocalHost();

        outgramPacket = new DatagramPacket(msg,1,serverAdress,8000);//send to port 8000
        datagramSocket.send(outgramPacket);//make the request to the server
        ingramPacket = new DatagramPacket(msg,msg.length);//set up a datagram packet to receive server's response
        datagramSocket.receive(ingramPacket);
        receivedmsg = new String(ingramPacket.getData(),0,ingramPacket.getLength());
        System.out.println(receivedmsg);//print the data received from the server
        datagramSocket.close();


    }

    public static void main(String[]args) throws IOException {
   UdpClient udpClient = new UdpClient();
   try {
       udpClient.go();
   }catch (Exception e){
       System.out.println(e);
   }
    }
}

server:


public class UdpServer {

public byte[]getTime(){
    Date d = new Date();
    return d.toString().getBytes(StandardCharsets.UTF_8);
}
public void go() throws IOException{

    DatagramPacket inDataPacket;
    DatagramPacket outDataPacket;
    DatagramSocket datagramSocket;
    InetAddress clientAdress;
    int clientPort;
    byte[]msg = new byte[10];//Incoming data buffer.ignored
    byte[]time;
    datagramSocket = new DatagramSocket(8000);//allocate a socket to man port 8000 for requests
    System.out.println("UDPserver :"+datagramSocket.getPort()+"local is:"+datagramSocket.getLocalPort());
    System.out.println("udpserver active on port 8000");
    while (true)
    {
        inDataPacket = new DatagramPacket(msg,msg.length);
        datagramSocket.receive(inDataPacket);//get the message
        clientAdress = inDataPacket.getAddress();
        clientPort = inDataPacket.getPort();
        time=getTime();
        outDataPacket = new DatagramPacket(time,time.length,clientAdress,clientPort);
        datagramSocket.send(outDataPacket);//send the packet

    }
}

    public static void main(String[]args){
    UdpServer udpServer = new UdpServer();
    try{
        udpServer.go();
    }catch (IOException e)
    {
        e.printStackTrace();
    }
    }

}

结果:
在这里插入图片描述

在这里插入图片描述
客户端接收一次数据之后即关闭连接,而服务端一直可以接收请求。

其他

使用socket类作为客户端链接网站:

public class Hzy {


    public static void main(String args[]) throws IOException {
    Socket socket = null;
    try {
        socket = new Socket("www.csdn.net", 80);
        System.out.println("socket连接成功");
    } catch (IOException e) {
        System.out.println("socket连接失败");
        e.printStackTrace();
    } finally {
        socket.close();
    }
}
        
    }

在这里插入图片描述
注意:如果host为不存在的域名,会发生报错

用ServerSocket创建一个web服务器:

public class Hzy {


    public static void main(String args[]) throws IOException {
        ServerSocket serverSocket = new ServerSocket(6666,1, InetAddress.getByName("127.0.0.1"));
        Socket socket = serverSocket.accept();
        InputStream inputStream = socket.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

        String getString = "";
        while (!"".equals(getString = bufferedReader.readLine())) {
            System.out.println(getString);
        }

        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("HTTP/1.1 200 OK\r\n\r\n".getBytes());
        outputStream.write(
                "<html><body><a href='http://www.baidu.com'>i am baidu.com welcome you!</a></body></html>".getBytes());
        outputStream.flush();

        inputStream.close();
        outputStream.close();
        socket.close();
        serverSocket.close();
    }

    }

这个代码不知道为什么打开浏览器还是没法访问,原因还未找到。

文件目录:
在这里插入图片描述
chartserver:


public class ChatServer {
	private static final int SOCKET_PORT = 52000;
	public static ArrayList<SocketBean> mSocketList = new ArrayList<SocketBean>();

	private void initServer() {
		try {
			// 创建一个ServerSocket,用于监听客户端Socket的连接请求
			ServerSocket server = new ServerSocket(SOCKET_PORT);
			while (true) {
				// 每当接收到客户端的Socket请求,服务器端也相应的创建一个Socket
				SocketBean socket = new SocketBean(DateUtil.getTimeId(), server.accept());
				mSocketList.add(socket);
				// 每连接一个客户端,启动一个ServerThread线程为该客户端服务
				new Thread(new ServerThread(socket)).start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		ChatServer server = new ChatServer();
		server.initServer();
	}
}

ServerThread


public class ServerThread implements Runnable {
	private SocketBean mSocket = null;
	private BufferedReader mReader = null;

	public ServerThread(SocketBean mSocket) throws IOException {
		this.mSocket = mSocket;
		mReader = new BufferedReader(new InputStreamReader(mSocket.socket.getInputStream()));
	}

	@Override
	public void run() {
		try {
			String content = null;
			// 循环不断地从Socket中读取客户端发送过来的数据
			while ((content = mReader.readLine()) != null) {
				System.out.println("content="+content);
				int pos = content.indexOf("|");
				// 包头格式为:动作名称|设备编号|昵称|时间|对方设备编号
				String head = content.substring(0, pos);
				String body = content.substring(pos+1);
				String[] splitArray = head.split(",");
				String action = splitArray[0];
				System.out.println("action="+action);
				if (action.equals("LOGIN")) {
					login(splitArray[1], splitArray[2], splitArray[3]);
				} else if (action.equals("LOGOUT")) {
					logout(splitArray[1]);
					break;
				} else if (action.equals("SENDMSG")) {
					sendmsg("RECVMSG", splitArray[2], splitArray[4], splitArray[1], body);
				} else if (action.equals("GETLIST")) {
					getlist(splitArray[1]);
				} else if (action.equals("SENDPHOTO")) {
					sendmsg("RECVPHOTO", splitArray[2], splitArray[4], splitArray[1], body);
				} else if (action.equals("SENDSOUND")) {
					sendmsg("RECVSOUND", splitArray[2], splitArray[4], splitArray[1], body);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void login(String deviceId, String nickName, String loginTime) throws IOException {
		for (int i=0; i<ChatServer.mSocketList.size(); i++) {
			SocketBean item = ChatServer.mSocketList.get(i);
			if (item.id.equals(mSocket.id)) {
				item.deviceId = deviceId;
				item.nickName = nickName;
				item.loginTime = loginTime;
				ChatServer.mSocketList.set(i, item);
				break;
			}
		}
	}
	
	private String getFriend() {
		String friends = "GETLIST,";
		for (SocketBean item : ChatServer.mSocketList) {
			if (item.deviceId!=null && item.deviceId.length()>0) {
				String friend = String.format("|%s,%s,%s", item.deviceId, item.nickName, item.loginTime);
				friends += friend;
			}
		}
		return friends;
	}
	
	private void getlist(String deviceId) throws IOException {
		for (int i=0; i<ChatServer.mSocketList.size(); i++) {
			SocketBean item = ChatServer.mSocketList.get(i);
			if (item.id.equals(mSocket.id) && item.deviceId.equals(deviceId)) {
				PrintStream ps = new PrintStream(item.socket.getOutputStream());
				ps.println(getFriend());
				break;
			}
		}
	}
	
	private void logout(String deviceId) throws IOException {
		for (int i=0; i<ChatServer.mSocketList.size(); i++) {
			SocketBean item = ChatServer.mSocketList.get(i);
			if (item.id.equals(mSocket.id) && item.deviceId.equals(deviceId)) {
				PrintStream ps = new PrintStream(item.socket.getOutputStream());
				ps.println("LOGOUT,|");
				item.socket.close();
				ChatServer.mSocketList.remove(i);
				break;
			}
		}
	}

	private void sendmsg(String respAction, String otherName, String otherId, String selfId, String message) throws IOException {
		for (int i=0; i<ChatServer.mSocketList.size(); i++) {
			SocketBean item = ChatServer.mSocketList.get(i);
			if (item.deviceId.equals(otherId)) {
				String content = String.format("%s,%s,%s,%s|%s", 
						respAction, selfId, otherName, DateUtil.getNowTime(), message);
				System.out.println("resp="+content);
				PrintStream ps = new PrintStream(item.socket.getOutputStream());
				ps.println(content);
				break;
			}
		}
	}

}

socketbean:


public class SocketBean {
	public String id;
	public Socket socket;
	public String deviceId;
	public String nickName;
	public String loginTime;
	
	public SocketBean(String id, Socket socket) {
		this.id = id;
		this.socket = socket;
		this.deviceId = "";
		this.nickName = "";
		this.loginTime = "";
	}

}

TestServer:


public class TestServer {
	private static final int SOCKET_PORT = 51000;

	private void initServer() {
		try {
			// 创建一个ServerSocket,用于监听客户端Socket的连接请求
			ServerSocket server = new ServerSocket(SOCKET_PORT);
			while (true) {
				Socket socket = server.accept();
				new Thread(new ServerThread(socket)).start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		TestServer server = new TestServer();
		server.initServer();
	}
	
	private class ServerThread implements Runnable {
		private Socket mSocket;
		private BufferedReader mReader;
		
		public ServerThread(Socket socket) throws IOException {
			mSocket = socket;
			mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
		}

		@Override
		public void run() {
			try {
				String content = null;
				// 循环不断地从Socket中读取客户端发送过来的数据
				while ((content = mReader.readLine()) != null) {
					System.out.println("收到客户端消息:"+content);
					PrintStream ps = new PrintStream(mSocket.getOutputStream());
					ps.println("hi,很高兴认识你");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
	
}

客户端:


public class MessageTransmit implements Runnable {
	private static final String TAG = "MessageTransmit";
	// 以下为Socket服务器的ip和端口,根据实际情况修改
	private static final String SOCKET_IP = "192.168.0.212";
	private static final int SOCKET_PORT = 51000;

	private Socket mSocket;
	private BufferedReader mReader = null;
	private OutputStream mWriter = null;

	@Override
	public void run() {
		mSocket = new Socket();
		try {
			mSocket.connect(new InetSocketAddress(SOCKET_IP, SOCKET_PORT), 3000);
			mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
			mWriter = mSocket.getOutputStream();
			// 启动一条子线程来读取服务器的返回数据
			new RecvThread().start();
			Looper.prepare();
			Looper.loop();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 定义接收UI线程的Handler对象,App向后台服务器发送消息
	public Handler mRecvHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			Log.d(TAG, "handleMessage: "+msg.obj);
			// 换行符相当于回车键,表示我写好了发出去吧
			String send_msg = msg.obj.toString()+"\n";
			try {
				mWriter.write(send_msg.getBytes("utf8"));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	};

	// 定义消息接收子线程,App从后台服务器接收消息
	private class RecvThread extends Thread {
		@Override
		public void run() {
			try {
				String content = null;
				while ((content = mReader.readLine()) != null) {
					// 读取到来自服务器的数据
					Message msg = Message.obtain();
					msg.obj = content;
					SocketActivity.mHandler.sendMessage(msg);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

}

public class ClientThread implements Runnable {
	private static final String TAG = "ClientThread";
	private static final String SOCKET_IP = "192.168.253.1";
	//private static final String SOCKET_IP = "192.168.0.212";
	private static final int SOCKET_PORT = 52000;
	public static final String REQUEST_URL = "http://192.168.253.1:8080/UploadTest";
	private Context mContext;
	private Socket mSocket;
	public Handler mRecvHandler;
	private BufferedReader mReader = null;
	private OutputStream mWriter = null;
	
	public static String ACTION_RECV_MSG = "com.example.network.RECV_MSG";
	public static String ACTION_GET_LIST = "com.example.network.GET_LIST";
	public static String CONTENT = "CONTENT";
	public static String SPLIT_LINE = "|";
	public static String SPLIT_ITEM = ",";
	public static String LOGIN = "LOGIN";
	public static String LOGOUT = "LOGOUT";
	public static String SENDMSG = "SENDMSG";
	public static String RECVMSG = "RECVMSG";
	public static String GETLIST = "GETLIST";
	public static String SENDPHOTO = "SENDPHOTO";
	public static String RECVPHOTO = "RECVPHOTO";
	public static String SENDSOUND = "SENDSOUND";
	public static String RECVSOUND = "RECVSOUND";

	public ClientThread(Context context) {
		mContext = context;
	}

	@Override
	public void run() {
		Log.d(TAG, "run");
		mSocket = new Socket();
		try {
			Log.d(TAG, "connect");
			mSocket.connect(new InetSocketAddress(SOCKET_IP, SOCKET_PORT), 3000);
			mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
			Log.d(TAG, "getOutputStream");
			mWriter = mSocket.getOutputStream();
			Log.d(TAG, "RecvThread");
			// 启动一条子线程来读取服务器相应的数据
			new RecvThread().start();
			Looper.prepare();
			// 定义接收UI线程的Handler对象,App向后台服务器发送消息
			// 如果是在Application中启动线程,则mRecvHandler要在线程启动后才能初始化
			// 并且要在Looper.prepare之后执行初始化动作
			mRecvHandler = new Handler() {
				@Override
				public void handleMessage(Message msg) {
					// 接收到UI线程的用户输入的数据
					try {
						mWriter.write(msg.obj.toString().getBytes("utf8"));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			};
			Looper.loop();
		} catch (Exception e) {
			e.printStackTrace();
			notify(99, e.getMessage());
		}
	}

	// 定义消息接收子线程,App从后台服务器接收消息
	private class RecvThread extends Thread {
		@Override
		public void run() {
			String content = null;
			try {
				while ((content = mReader.readLine()) != null) {
					// 读取到来自服务器的数据之后,发送消息通知
					ClientThread.this.notify(0, content);
				}
			} catch (Exception e) {
				e.printStackTrace();
				ClientThread.this.notify(97, e.getMessage());
			}
		}
	}

	private void notify(int type, String message) {
		if (type == 99) {
			String content = String.format("%s%s%s%s", "ERROR", SPLIT_ITEM, SPLIT_LINE, message);
			Intent intent1 = new Intent(ACTION_RECV_MSG);
			intent1.putExtra(CONTENT, content);
			mContext.sendBroadcast(intent1);
			Intent intent2 = new Intent(ACTION_GET_LIST);
			intent2.putExtra(CONTENT, content);
			mContext.sendBroadcast(intent2);
		} else {
			int pos = message.indexOf(SPLIT_LINE);
			String head = message.substring(0, pos - 1);
			String[] splitArray = head.split(SPLIT_ITEM);
			String action = "";
			if (splitArray[0].equals(RECVMSG) 
					|| splitArray[0].equals(RECVPHOTO) 
					|| splitArray[0].equals(RECVSOUND)) {
				action = ACTION_RECV_MSG;
			} else if (splitArray[0].equals(GETLIST)) {
				action = ACTION_GET_LIST;
			}
			Log.d(TAG, "action=" + action + ", message=" + message);
			Intent intent = new Intent(action);
			intent.putExtra(CONTENT, message);
			mContext.sendBroadcast(intent);
		}
	}

}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java开发技术大全 电子版 第1篇Java基础知识入门. 第1章Java开发运行环境2 1.1Java的运行环境与虚拟机2 1.2Java开发环境4 1.2.1JDK的安装4 1.2.2如何设置系统环境变量6 1.2.3编译命令的使用8 1.2.4解释执行命令的使用10 1.2.5UltraEdit的使用11 1.3一个简单的Java应用程序14 1.4一个简单的Java程序16 1.5本章小结18 第2章Java语言基础19 2.1Java语言的特点19 2.2Java程序的构成21 2.3数据类 型23 2.3.1基本数据类型23 2.3.2常量25 2.3.3变量26 2.3.4整型数据27 .2.3.5浮点型数据29 2.3.6字符型数据30 2.3.7布尔型数据32 2.3.8变量赋初值33 2.3.9变量的作用域34 2.3.10数据类型转换34 2.4运算符与表达式37 2.4.1算术运算符和算术表达式38 2.4.2关系运算符和关系表达式43 2.4.3逻辑运算符和逻辑表达式44 2.4.4条件运算符和条件表达式48 2.4.5位运算符和位运算表达式50 2.4.6赋值运算符和赋值表达式53 2.4.7表达式的求值顺序55 2.5流程控制语句58 2.5.1三种基本控制结构58 2.5.2表达式语句和空语句59 2.5.3块语句60 2.5.4if~else分支语句61 2.5.5多路分支switch~case语句69 2.5.6当型循环while语句71 2.5.7直到型循环do~while语句72 2.5.8当型循环for语句74 2.5.9循环的嵌套78 2.5.10跳转语句break80 2.5.11跳转语句continue82 2.6程序文本的风格84 2.6.1注释84 2.6.2程序的格式编排87 2.7基础语法实战演习88 2.7.1判断闰年88 2.7.2求最大公约数和最小公倍数89 2.7.3Fibonacci数列90 2.7.4逆向输出数字91 2.7.5求水仙花数92 2.7.6输出图形93 2.7.7输出九九口诀表94 2.8本章小结95 第2篇Java面向对象编程 第3章对象和类98 3.1面向对象的基本概念98 3.1.1对象98 3.1.2类99 3.1.3消息101 3.1.4面向对象的4个基本特征101 3.2类与对象104 3.2.1类的基本结构104 3.2.2类的声明104 3.2.3创建类体105 3.2.4对象的生命周期106 3.2.5对象的创建106 3.2.6对象的使用108 3.2.7对象的释放和垃圾收集机制108 3.3成员变量的定义与使用109 3.3.1成员变量的定义109 3.3.2成员变量的访问权限110 3.3.3实例成员变量和静态成员变量114 3.4方法的定义和实现116 3.4.1方法的声明117 3.4.2创建方法体与return语句117 3.4.3局部变量和成员变量的区别119 3.4.4方法的访问权限121 3.5方法的调用121 3.5.1方法调用的形式121 3.5.2方法调用的参数123 3.5.3隐含参数this127 3.6构造方法128 3.6.1无参数构造方法的定义和使用129 3.6.2带参数构造方法的定义和使用131 3.6.3this关键字和构造方法的调用132 3.7静态方法133 3.7.1静态方法的声明和定义134 3.7.2静态方法和实例方法的区别134 3.7.3静态代码块136 3.7.4再论静态成员变量137 3.8main()方法和命令行参数139 3.9结束方法141 3.10本地方法141 3.11本章小结144 第4章继承与多态145 4.1继承的基本原理145 4.2子类对父类的继承146 4.3属性隐藏和方法的覆盖148 4.3.1属性的隐藏148 4.3.2方法的覆盖151 4.4构造方法的继承154 4.5super的使用156 4.5.1用super引用父类的成员156 4.5.2使用super调用父类的构造方法157 4.6继承的内部处理158 4.7多态的基本概念159 4.8重载159 4.8.1普通方法的重载160 4.8.2构造方法的重载161 4.8.3重载的解析163 4.8.4重载与覆盖的区别165 4.9运行时多态165 4.9.1实例方法的运行时多态165 4.9.2成员变量运行时的表现167 4.9.3静态方法运行时
好的,这是一个可以在VMware中使用的C语言的UDP通信程序,包括服务器和客户端代码,同时服务器端支持多线程通信。 VMware中使用UDP通信时,需要在虚拟机的网络设置中将网络适配器设置为“桥接模式”,这样虚拟机就可以使用与主机相同的网络,从而实现与主机之间的通信。 首先是服务器端代码: ```c #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include<pthread.h> #define SERVER_PORT 8888 #define MAX_BUFFER_SIZE 1024 void *thread_recv(void *arg) { int sockfd = *(int*)arg; struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); char buffer[MAX_BUFFER_SIZE]; while(1) { int n = recvfrom(sockfd, buffer, MAX_BUFFER_SIZE, 0, (struct sockaddr *)&client_addr, &addr_len); if(n < 0) { perror("recvfrom error"); continue; } buffer[n] = '\0'; printf("[Server] receive message from %s:%d: %s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer); } close(sockfd); } int main() { // 创建 UDP socket int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("create socket error"); exit(-1); } // 绑定监听地址 struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind error"); exit(-1); } // 创建多个线程接收数据 pthread_t thread_id[10]; for(int i=0; i<10; i++) { if(pthread_create(&thread_id[i], NULL, thread_recv, (void *)&sockfd) != 0) { perror("create thread error"); exit(-1); } } // 等待线程结束 for(int i=0; i<10; i++) { pthread_join(thread_id[i], NULL); } return 0; } ``` 然后是客户端代码: ```c #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #define SERVER_IP "192.168.1.100" // 虚拟机的IP地址 #define SERVER_PORT 8888 #define MAX_BUFFER_SIZE 1024 int main() { // 创建 UDP socket int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("create socket error"); exit(-1); } // 设置服务器地址 struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr); // 发送数据 char buffer[MAX_BUFFER_SIZE]; int n; while(1) { printf("[Client] please input message: "); fgets(buffer, MAX_BUFFER_SIZE, stdin); buffer[strlen(buffer)-1] = '\0'; n = sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&server_addr, sizeof(server_addr)); if(n < 0) { perror("sendto error"); continue; } if(strcmp(buffer, "exit") == 0) { break; } } close(sockfd); return 0; } ``` 在客户端代码中,我们需要将服务器的 IP 地址设置为虚拟机的 IP 地址,这样客户端才能够与虚拟机中的服务器进行通信。 注意:由于 UDP 是不可靠的传输协议,因此在发送和接收数据时,需要对 `sendto` 和 `recvfrom` 函数返回值进行判断以确保数据传输的正确性。同时,由于 UDP 是无连接的,因此客户端发送数据时需要自己指定服务器的 IP 和端口号。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值