鱼C论坛

 找回密码
 立即注册
查看: 8371|回复: 65

[经验总结] 我的编程,我的路

[复制链接]
发表于 2014-1-14 18:55:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
其实我根本就没深入学习编程,只能说是了解过,了解汇编,刷个板子,报过学习班,交了1万多大洋。没找到嵌入式的工作,后来就改做网络工程师了,考了MCP,过了CCNA。玩了几个月思科2900系列交换,路由之类的。3500系列,4000系列只见过没操作过。在国内企业干过2年,用的都是华为,华3C。玩了几个月LINUX,搞过几个月自己的网站论坛,基本都不长,就是单位需要 我就去学一下,不用了我就忘了,这么多年下来,没有一个精通的。全都算是了解吧。说到编程,C,C++,JAVA,都学了几个月。后来在论坛学了点CE破解之类的。
最后剩下的东西,就是会用按键精灵写写WG脚本,有难度的都没突破,依旧和新手一样,用着简单是for,if ,do,loop, sub 没有太大的起色。日子还得过,学习和生活同步进行中。继续坚持一次,每天写一个小功能,今天开始写一个客户端和服务器的小程序,然后每天在上面加一个功能,逐步达到服务器让客户端干什么就能干什么。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2014-1-14 19:04:10 | 显示全部楼层
本帖最后由 ╃烦了 于 2014-1-14 19:05 编辑

今天开始记录吧。希望我能坚持一下,性格最大的缺点就是急躁,我媳妇说这个是浮躁,人的沉淀不够就容易浮躁。我之所以开始捡起编程,是因为有一个强大的背景压力,万般无奈只能寄托希望于此。

标题:编程日志 初级(1)
日期:2014年1月14日19:03
目标:收集客户端和服务器的源代码
执行:现在出去买饭,回来后开始执行
结果:等待接受中
改善:等待结果后判断
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 19:31:11 | 显示全部楼层
执行开始:
搜索找到一个JAVA版本的。
代码如下:
功能说明:
TCP服务器提供文件下载服务,服务器支持多线程。
TCP Client从服务器上下载指定的文件,Client也支持多线程。
分服务器代码和客户端代码:ServerOneDownload.java 为服务器代码
DownLoadClient.java为客户端代码、DownFileThread.java为客户端代码

详细代码:
ServerOneDownload.java

//file:DownloadServer.java   
import java.net.*;  
import java.io.*;  
class ServerOneDownload extends Thread {  
    private Socket socket = null;  
    private String downloadRoot = null;  
    private static final int Buffer = 8 * 1024;  
    public ServerOneDownload(Socket socket, String downloadRoot) {  
        super();  
        this.socket = socket;  
        this.downloadRoot = downloadRoot;  
        start();  
    }  
    // 检查文件是否真实存在,核对下载密码,若文件不存在或密码错误,则返回-1,否则返回文件长度  
    // 此处只要密码不为空就认为是正确的  
    private long getFileLength(String fileName, String password) {  
        // 若文件名或密码为null,则返回-1  
        if ((fileName == null) || (password == null))  
            return -1;  
        // 若文件名或密码长度为0,则返回-1  
        if ((fileName.length() == 0) || (password.length() == 0))  
            return -1;  
        String filePath = downloadRoot + fileName; // 生成完整文件路径  
        System.out.println("DownloadServer getFileLength----->" + filePath);  
        File file = new File(filePath);  
        // 若文件不存在,则返回-1  
        if (!file.exists())  
            return -1;  
        return file.length(); // 返回文件长度  
    }  
    // 用指定输出流发送指定文件  
    private void sendFile(DataOutputStream out, String fileName)  
            throws Exception {  
        String filePath = downloadRoot + fileName; // 生成完整文件路径  
        // 创建与该文件关联的文件输入流  
        FileInputStream in = new FileInputStream(filePath);  
        System.out.println("DownloadServer sendFile----->" + filePath);  
        byte[] buf = new byte[Buffer];  
        int len;  
        // 反复读取该文件中的内容,直到读到的长度为-1  
        while ((len = in.read(buf)) >= 0) {  
            out.write(buf, 0, len); // 将读到的数据,按读到的长度写入输出流  
            out.flush();  
        }  
        out.close();  
        in.close();  
    }  
    // 提供下载服务  
    public void download() throws IOException {  
        System.out.println("启动下载... ");  
        System.out.println("DownloadServer currentThread--->"  
                + currentThread().getName());  
        System.out.println("DownloadServer currentThread--->"  
                + currentThread().getId());  
        // 获取socket的输入流并包装成BufferedReader  
        BufferedReader in = new BufferedReader(new InputStreamReader(  
                socket.getInputStream()));  
        // 获取socket的输出流并包装成DataOutputStream  
        DataOutputStream out = new DataOutputStream(socket.getOutputStream());  
        try {  
            String parameterString = in.readLine(); // 接收下载请求参数  
            // 下载请求参数字符串为自定义的格式,由下载文件相对于下载根目录的路径和  
            // 下载密码组成,两者间以字符 "@ "分隔,此处按 "@ "分割下载请求参数字符串  
            String[] parameter = parameterString.split("@ ");  
            String fileName = parameter[0]; // 获取相对文件路径  
            String password = parameter[1]; // 获取下载密码  
            // 打印请求下载相关信息  
            System.out.print(socket.getInetAddress().getHostAddress()  
                    + "提出下载请求, ");  
            System.out.println("请求下载文件: " + fileName);  
            // 检查文件是否真实存在,核对下载密码,获取文件长度  
            long len = getFileLength(fileName, password);  
            System.out.println("download fileName----->" + fileName);  
            System.out.println("download password----->" + password);  
            out.writeLong(len); // 向客户端返回文件大小  
            out.flush();  
            // 若获取的文件长度大于等于0,则允许下载,否则拒绝下载  
            if (len >= 0) {  
                System.out.println("允许下载 ");  
                System.out.println("正在下载文件 " + fileName + "... ");  
                sendFile(out, fileName); // 向客户端发送文件  
                System.out.println(fileName +": "+"下载完毕 ");  
            } else {  
                System.out.println("下载文件不存在或密码错误,拒绝下载! ");  
            }  
        } catch (Exception e) {  
            System.out.println(e.toString());  
        } finally {  
            socket.close(); // 关闭socket  
        }  
    }  
    @Override  
    public void run() {  
        try {  
            download();  
        } catch (IOException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        // TODO Auto-generated method stub  
        super.run();  
    }  
}  
public class DownloadServer {  
    private final static int port = 65525;  
    private static String root = "C:\\ "; // 下载根目录  
    public static void main(String[] args) throws IOException {  
        String temp = null;  
        // 监听端口  
        try {  
            // 包装标准输入为BufferedReader  
            BufferedReader systemIn = new BufferedReader(new InputStreamReader(  
                    System.in));  
            while (true) {  
                System.out.print("请输入下载服务器的下载根目录: ");  
                root = systemIn.readLine().trim(); // 从标准输入读取下载根目录  
                File file = new File(root);  
                // 若该目录确实存在且为目录,则跳出循环  
                if ((file.exists()) && (file.isDirectory())) {  
                    temp = root.substring(root.length() - 1, root.length());  
                    if (!temp.equals("\\"))  
                        root += "\\";  
                }  
                break;  
            }  
        } catch (Exception e) {  
            System.out.println(e.toString());  
        }  
        ServerSocket serverSocket = new ServerSocket(port);  
        System.out.println("Server start...");  
        try {  
            while (true) {  
                Socket socket = serverSocket.accept();  
                new ServerOneDownload(socket, root);  
            }  
        } finally {  
            serverSocket.close();  
        }  
    }  
}  

客户端:
DownLoadClient.java
//file:DownLoadClient.java   
package org.piaozhiye.study;  
import java.io.IOException;  
import java.net.Socket;  
import android.app.Activity;  
import android.os.Bundle;  
import android.view.View;  
import android.widget.Button;  
import android.widget.EditText;  
public class DownLoadClient extends Activity {  
    private Button download = null;  
    private EditText et_serverIP = null;  
    private EditText et_fileName= null;  
    private String downloadFile = null;  
    private final static int PORT = 65525;  
    private final static String defaultIP = "192.168.0.100";  
    private static String serverIP = null;  
    private Socket socket;  
    /** Called when the activity is first created. */  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        download = (Button)findViewById(R.id.download);  
        et_serverIP= (EditText)findViewById(R.id.et_serverip);  
        et_fileName = (EditText)findViewById(R.id.et_filename);  
        et_serverIP.setText("192.168.0.100");  
        
      download.setOnClickListener(new View.OnClickListener() {  
              
            @Override  
            public void onClick(View v) {  
                 serverIP = et_serverIP.getText().toString();  
                 if(serverIP == null){  
                     serverIP = defaultIP;  
                 }  
                 System.out.println("DownLoadClient serverIP--->" + serverIP );  
                    System.out.println("DownLoadClient MainThread--->" + Thread.currentThread().getId() );  
                     
                try{  
                    socket = new Socket(serverIP, PORT);  
                     
                }catch(IOException e){  
                     
                }  
                 downloadFile = et_fileName.getText().toString();  
            Thread downFileThread = new Thread(new DownFileThread(socket, downloadFile));  
            downFileThread.start();  
                System.out.println("DownLoadClient downloadFile--->" + downloadFile );  
            }  
        });  
         
    }  
}  


执行任务:
DownFileThread.java
package org.piaozhiye.study;  
import java.io.BufferedInputStream;  
import java.io.DataInputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.OutputStreamWriter;  
import java.io.PrintWriter;  
import java.net.Socket;  
public class DownFileThread extends Thread {  
    private Socket socket;  
    private String downloadFile;  
    private final static int Buffer = 8 * 1024;  
    public DownFileThread(Socket socket, String downloadFile) {  
        super();  
        this.socket = socket;  
        this.downloadFile = downloadFile;  
    }  
    public Socket getSocket() {  
        return socket;  
    }  
    public void setSocket(Socket socket) {  
        this.socket = socket;  
    }  
    public String getDownloadFile() {  
        return downloadFile;  
    }  
    public void setDownloadFile(String downloadFile) {  
        this.downloadFile = downloadFile;  
    }  
    // 向服务器提出下载请求,返回下载文件的大小  
    private long request(String fileName, String password) throws IOException {  
        // 获取socket的输入流并包装成DataInputStream  
        DataInputStream in = new DataInputStream(socket.getInputStream());  
        // 获取socket的输出流并包装成PrintWriter  
        PrintWriter out = new PrintWriter(new OutputStreamWriter(  
                socket.getOutputStream()));  
        // 生成下载请求字符串  
        String requestString = fileName + "@ " + password;  
        out.println(requestString); // 发出下载请求  
        out.flush();  
        return in.readLong(); // 接收并返回下载文件长度  
    }  
    // 接收并保存文件  
    private void receiveFile(String localFile) throws Exception {  
        // 获取socket的输入流并包装成BufferedInputStream  
        BufferedInputStream in = new BufferedInputStream(  
                socket.getInputStream());  
        // 获取与指定本地文件关联的文件输出流  
        FileOutputStream out = new FileOutputStream(localFile);  
        byte[] buf = new byte[Buffer];  
        int len;  
        // 反复读取该文件中的内容,直到读到的长度为-1  
        while ((len = in.read(buf)) >= 0) {  
            out.write(buf, 0, len); // 将读到的数据,按读到的长度写入输出流  
            out.flush();  
        }  
        out.close();  
        in.close();  
    }  
    // 从服务器下载文件  
    public void download(String downloadFile) throws Exception {  
        try {  
            String password = "password";  
            // String downloadFile ="imissyou.mp3";  
            String localpath = "/sdcard/";  
            String localFile = localpath + downloadFile;  
            long fileLength = request(downloadFile, password);  
            // 若获取的文件长度大于等于0,说明允许下载,否则说明拒绝下载  
            if (fileLength >= 0) {  
                System.out.println("fileLength: " + fileLength + " B");  
                System.out.println("downing...");  
                receiveFile(localFile); // 从服务器接收文件并保存至本地文件  
                System.out.println("file:" + downloadFile + " had save to "  
                        + localFile);  
            } else {  
                System.out.println("download " + downloadFile + " error! ");  
            }  
        } catch (IOException e) {  
            System.out.println(e.toString());  
        } finally {  
            socket.close(); // 关闭socket  
        }  
    }  
    @Override  
    public void run() {  
        System.out.println("DownFileThread currentThread--->"  
                + DownFileThread.currentThread().getId());  
        // TODO Auto-generated method stub  
        try {  
            download(downloadFile);  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        super.run();  
    }  
      
}  



分析判断:留作参考继续搜索
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 19:44:37 | 显示全部楼层
继续执行:
找到一个QQ的版本的,JAVA代码有些乱用处不大留着参考吧。
服务器版:
package com.way.chat.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.way.chat.common.util.Constants;
import com.way.chat.common.util.MyDate;

/**
* 服务器,接受用户登录、离线、转发消息
*
* @author way
*
*/
public class Server {
        private ExecutorService executorService;// 线程池
        private ServerSocket serverSocket = null;
        private Socket socket = null;
        private boolean isStarted = true;

        public Server() {
                try {
                        // 创建线程池,池中具有(cpu个数*50)条线程
                        executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
                                        .availableProcessors() * 50);
                        serverSocket = new ServerSocket(Constants.SERVER_PORT);
                } catch (IOException e) {
                        e.printStackTrace();
                        quit();
                }
        }

        public void start() {
                System.out.println(MyDate.getDateCN() + " 服务器已启动...");
                try {
                        while (isStarted) {
                                socket = serverSocket.accept();
                                String ip = socket.getInetAddress().toString();
                                System.out.println(MyDate.getDateCN() + " 用户:" + ip + " 已建立连接");
                                // 为支持多用户并发访问,采用线程池管理每一个用户的连接请求
                                if (socket.isConnected())
                                        executorService.execute(new SocketTask(socket));// 添加到线程池
                        }
                        if (socket != null)
                                socket.close();
                        if (serverSocket != null)
                                serverSocket.close();
                } catch (IOException e) {
                        e.printStackTrace();
                        // isStarted = false;
                }
        }

        private final class SocketTask implements Runnable {
                private Socket socket = null;
                private InputThread in;
                private OutputThread out;
                private OutputThreadMap map;

                public SocketTask(Socket socket) {
                        this.socket = socket;
                        map = OutputThreadMap.getInstance();
                }

                @Override
                public void run() {
                        out = new OutputThread(socket, map);//
                        // 先实例化写消息线程,(把对应用户的写线程存入map缓存器中)
                        in = new InputThread(socket, out, map);// 再实例化读消息线程
                        out.setStart(true);
                        in.setStart(true);
                        in.start();
                        out.start();
                }
        }

        /**
         * 退出
         */
        public void quit() {
                try {
                        this.isStarted = false;
                        serverSocket.close();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }

        public static void main(String[] args) {
                new Server().start();
        }
}


客户 端
package com.way.client;


import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.Socket;


/**
* 客户端
*
* @author way
*
*/

public class Client {

        private Socket client;

private ClientThread clientThread;
       
private String ip;
       
private int port;

       
public Client(String ip, int port)
{
               
this.ip = ip;       
this.port = port;

}

       
public boolean start()
{
               
try
{
                       
client = new Socket();
                       
// client.connect(new InetSocketAddress(Constants.SERVER_IP,
                       
// Constants.SERVER_PORT), 3000);

                        client.connect(new InetSocketAddress(ip, port), 3000);

                        if (client.isConnected())
{
                               
// System.out.println("Connected..");
                               
clientThread = new ClientThread(client);

                                clientThread.start();

                        }
                }

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

                        return false;
                }

                return true;
        }

       
// 直接通过client得到读线程
       
public ClientInputThread getClientInputThread()
{
                return clientThread.getIn();
        }


        // 直接通过client得到写线程
       
public ClientOutputThread getClientOutputThread()
{
                return clientThread.getOut();
        }

       
// 直接通过client停止读写消息
       
public void setIsStart(boolean isStart)
{
                clientThread.getIn().setStart(isStart);

                clientThread.getOut().setStart(isStart);
        }

       
        public class ClientThread extends Thread
{

                private ClientInputThread in;
       
        private ClientOutputThread out;

       

        public ClientThread(Socket socket)
{
                        in = new ClientInputThread(socket);

                        out = new ClientOutputThread(socket);

                }

               
public void run()
{
                        in.setStart(true);

                        out.setStart(true);

                        in.start();

                        out.start();
                }

               
// 得到读消息线程
               
public ClientInputThread getIn()
{
                        return in;
                }

               
// 得到写消息线程
               
public ClientOutputThread getOut()
{
                        return out;
                }
        }
}

分析判断:还是没找到我想要的。简单的。


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 19:47:14 | 显示全部楼层
以上2个代码的分析,一个是对文件的操作,一个是对信息接收发送的操作。暂时记录这些。继续找
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 19:49:31 | 显示全部楼层
总结:以上2次操作发现没有适合的入手点,即使找到了代码,自己也改不明白,出了BUG也调不了。
搜索方向改变:找服务器与客户端通信原理
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 19:59:44 | 显示全部楼层
搜索目标:服务器与客户端通信原理
继续执行结果如下:
学习任何东西,我们只要搞清楚其原理,就会触类旁通。现在结和我所学,我想总结一下客户端到服务器端的通信过程。只有明白了原理,我们才会明白当我们程序开发过程中错误的问题会出现在那,才会更好的解决问题。

  我们首先要了解一个概念性的词汇:Socket

      socket的英文原义是“孔”或“插座”。作为进程通信机制,取后一种意思。通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄。(其实就是两个程序通信用的。)socket非常类似于电话的插座。以一个电话网为例。电话的通话双方相当于相互通信的2个程序,电话号码可以当作是IP地址。任何用户在通话之前,首先要占有一部电话机,相当于申请一个socket;同时要知道对方的号码(IP地址),相当于对方有一个固定的socket。然后向对方拨号呼叫,相当于发出连接请求。对方假如在场并空闲,拿起电话话筒,双方就可以正式通话,相当于连接成功。双方通话的过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机相当于关闭socket,撤消连接,通信完成。

     以上通信是以两个人通话做为事例来在概的说明了下通信,但是现在假如通信中的一个人是外国人(说英语),一个人是中国人(说普通话),他们俩相互通信的话,都不能听明白对方说的是什么,那么他们的沟通就不能够完成。但是如果我们给一个规定,给通话双方,只能讲普通话,那么双方沟通就没有障碍了。这就引出来了通信协议。

有两种类型:(Tcp协议与Udp协议):

     Tcp协议与Udp协议是在两硬件设备上进行通信传输的一种数据语法。

– 流式Socket(STREAM):
是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低;Tcp:是以流的形式来传的。

– 数据报式Socket(DATAGRAM):
是一种无连接的Socket,对应于无连接的UDP服务应用.不安全(丢失,顺序混乱,在接收端要分析重排及要求重发),但效率高.Udp:将数据包拆开为若干份编号后来传输。在传输的过程中容易出现数据的丢失。但是传输速度要比TCP的快。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:06:31 | 显示全部楼层
OK。了解原理以后,选编程语言,之前学的是C和C++比较多,所以选C++。然后选编译软件。
对一款插件比较感兴趣,所以采用采用vc6.0编写。
执行:下载编译器。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:11:30 | 显示全部楼层
Socket的通信流程
demo.jpg
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:12:12 | 显示全部楼层
服务器端:
–  申请一个socket (socketWatch)用来监听的

–  绑定到一个IP地址和一个端口上

–  开启侦听,等待接授客户端的连接

–  当有连接时创建一个用于和连接进来的客户端进行通信的socket(socketConnection)

–  即续监听,等侍下一个客户的连接
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:12:44 | 显示全部楼层
服务器代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net;//IPAdress,IPEndPoint(ip和端口)类
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace MyChatRoomServer
{
    public partial class FChatServer : Form
    {
        public FChatServer()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;//关闭 对 文本框  的跨线程操作检查
        }

        Thread threadWatch = null;//负责监听 客户端 连接请求的 线程
        Socket socketWatch = null;//负责监听的 套接字

        private void btnBeginListen_Click(object sender, EventArgs e)
        {
            //创建 服务端 负责监听的 套接字,参数(使用IP4寻址协议,使用流式连接,使用TCP协议传输数据)
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
           //获得文本框中的 IP地址对象
            IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
            //创建 包含 ip 和 port 的网络节点对象
            IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
            //将 负责监听 的套接字 绑定到 唯一的IP和端口上
            socketWatch.Bind(endpoint);
            //设置监听队列的长度
            socketWatch.Listen(10);

            //创建 负责监听的线程,并传入监听方法
            threadWatch = new Thread(WatchConnecting);
            threadWatch.IsBackground = true;//设置为后台线程
            threadWatch.Start();//开启线程
            ShowMsg("服务器启动监听成功~");
            //IPEndPoint
            //socketWatch.Bind(
        }
        //保存了服务器端 所有负责和客户端通信的套接字
        Dictionary<string, Socket> dict = new Dictionary<string, Socket>();
        //保存了服务器端 所有负责调用 通信套接字.Receive方法 的线程
        Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>();

        //Socket sokConnection = null;
        /// <summary>
        /// 监听客户端请求的方法
        /// </summary>
        void WatchConnecting()
        {
            while (true)//持续不断的监听新的客户端的连接请求
            {
                //开始监听 客户端 连接请求,注意:Accept方法,会阻断当前的线程!
                Socket sokConnection = socketWatch.Accept();//一旦监听到客户端的请求,就返回一个负责和该客户端通信的套接字 sokConnection
                //sokConnection.Receive
                //向 列表控件中 添加一个 客户端的ip端口字符串,作为客户端的唯一标识
                lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());
                //将 与客户端通信的 套接字对象 sokConnection 添加到 键值对集合中,并以客户端IP端口作为键
                dict.Add(sokConnection.RemoteEndPoint.ToString(), sokConnection);
               
                //创建 通信线程
                ParameterizedThreadStart pts = new ParameterizedThreadStart(RecMsg);
                Thread thr = new Thread(pts);
                thr.IsBackground = true;//设置为
                thr.Start(sokConnection);//启动线程 并为线程要调用的方法RecMsg 传入参数sokConnection

                dictThread.Add(sokConnection.RemoteEndPoint.ToString(), thr);//将线程 保存在 字典里,方便大家以后做“踢人”功能的时候用

                ShowMsg("客户端连接成功!" + sokConnection.RemoteEndPoint.ToString());
                //sokConnection.RemoteEndPoint 中保存的是 当前连接客户端的 Ip和端口
            }
        }

        /// <summary>
        /// 服务端 负责监听 客户端 发送来的数据的 方法
        /// </summary>
        void RecMsg(object socketClientPara)
        {
            Socket socketClient = socketClientPara as Socket;
            while (true)
            {
                //定义一个 接收用的 缓存区(2M字节数组)
                byte[] arrMsgRec = new byte[1024 * 1024 * 2];
                //将接收到的数据 存入 arrMsgRec 数组,并返回 真正接收到的数据 的长度
                int length=-1;
                try
                {
                    length = socketClient.Receive(arrMsgRec);
                }
                catch (SocketException ex)
                {
                    ShowMsg("异常:" + ex.Message);
                    //从 通信套接字 集合中 删除 被中断连接的 通信套接字对象
                    dict.Remove(socketClient.RemoteEndPoint.ToString());
                    //从 通信线程    结合中 删除 被终端连接的 通信线程对象
                    dictThread.Remove(socketClient.RemoteEndPoint.ToString());
                    //从 列表中 移除 被中断的连接 ip:Port
                    lbOnline.Items.Remove(socketClient.RemoteEndPoint.ToString());
                    break;
                }
                catch (Exception ex)
                {
                    ShowMsg("异常:" + ex.Message);
                    break;
                }
                if (arrMsgRec[0] == 0)//判断 发送过来的数据 的第一个元素是 0,则代表发送来的是 文字数据
                {
                    //此时 是将 数组 所有的元素 都转成字符串,而真正接收到的 只有服务端发来的几个字符
                    string strMsgRec = System.Text.Encoding.UTF8.GetString(arrMsgRec,1, length-1);
                    ShowMsg(strMsgRec);
                }
                else if (arrMsgRec[0] == 1)//如果是1 ,则代表发送过来的是 文件数据(图片/视频/文件....)
                {
                    SaveFileDialog sfd = new SaveFileDialog();//保存文件选择框对象
                    if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)//用户选择文件路径后
                    {
                        string fileSavePath = sfd.FileName;//获得要保存的文件路径
                        //创建文件流,然后 让文件流来 根据路径 创建一个文件
                        using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))
                        {
                            fs.Write(arrMsgRec, 1, length-1);
                            ShowMsg("文件保存成功:" + fileSavePath);
                        }
                    }
                }
            }
        }

        //发送消息到客户端
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(lbOnline.Text))
            {
                MessageBox.Show("请选择要发送的好友");
            }
            else
            {
                string strMsg = txtMsgSend.Text.Trim();
                //将要发送的字符串 转成 utf8对应的字节数组
                byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
                //获得列表中 选中的KEY
                string strClientKey = lbOnline.Text;
                //通过key,找到 字典集合中对应的 与某个客户端通信的 套接字的 send方法,发送数据给对方
                try
                {
                    dict[strClientKey].Send(arrMsg);
                    //sokConnection.Send(arrMsg);
                    ShowMsg("发送了数据出去:" + strMsg);
                }
                catch (SocketException ex)
                {
                    ShowMsg("发送时异常:"+ex.Message);
                }
                catch (Exception ex)
                {
                    ShowMsg("发送时异常:" + ex.Message);
                }
            }
        }

        //服务端群发消息
        private void btnSendToAll_Click(object sender, EventArgs e)
        {
            string strMsg = txtMsgSend.Text.Trim();
            //将要发送的字符串 转成 utf8对应的字节数组
            byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
            foreach (Socket s in dict.Values)
            {
                s.Send(arrMsg);
            }
            ShowMsg("群发完毕!:)");
        }

        #region 显示消息
        /// <summary>
        /// 显示消息
        /// </summary>
        /// <param name="msg"></param>
        void ShowMsg(string msg)
        {
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:13:42 | 显示全部楼层
客户端:
–  申请一个socket(socketClient)

–  连接服务器(指明IP地址和端口号)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:15:40 | 显示全部楼层
代码如下:
using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;



using System.Net.Sockets;

using System.Net;

using System.Threading;



namespace MyChatRoomClient

{

    public partial class FChatClient : Form

    {

        public FChatClient()

        {

            InitializeComponent();

            TextBox.CheckForIllegalCrossThreadCalls = false;

        }

        Thread threadClient = null; //客户端 负责 接收 服务端发来的数据消息的线程

        Socket socketClient = null;//客户端套接字



//客户端发送连接请求到服务器

        private void btnConnect_Click(object sender, EventArgs e)

        {

            IPAddress address = IPAddress.Parse(txtIP.Text.Trim());//获得IP

            IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));//网络节点

//创建客户端套接字

            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //向 指定的IP和端口 发送连接请求

            socketClient.Connect(endpoint);

            //客户端 创建线程 监听服务端 发来的消息

            threadClient = new Thread(RecMsg);

            threadClient.IsBackground = true;

            threadClient.Start();

        }

        /// <summary>

/// 监听服务端 发来的消息

/// </summary>

        void RecMsg()

        {

            while (true)

            {

                //定义一个 接收用的 缓存区(2M字节数组)

                byte[] arrMsgRec = new byte[1024 * 1024 * 2];

                //将接收到的数据 存入 arrMsgRec 数组,并返回 真正接收到的数据 的长度

               int length=  socketClient.Receive(arrMsgRec);

                //此时 是将 数组 所有的元素 都转成字符串,而真正接收到的 只有服务端发来的几个字符

               string strMsgRec = System.Text.Encoding.UTF8.GetString(arrMsgRec, 0, length);

                ShowMsg(strMsgRec);

            }

        }





        void ShowMsg(string msg)

        {

            txtMsg.AppendText(msg + "\r\n");

        }

    }

}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:18:10 | 显示全部楼层
上面的代码是ASP.Net的、
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:20:23 | 显示全部楼层
发现个问题,不同的编程语言写出来的这套东西,基本原理都一样。唯一是就开头的部分,不同的国籍的人都需要跟电脑硬件沟通,都需要表明自己是哪国的语言,然后根据自己国家的语法跟电脑说话,这样电脑就明白了 。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:23:34 | 显示全部楼层
通信过程图
connection.jpg
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:25:07 | 显示全部楼层
通过以上流程图我们可以看出,客户端与服务器端之间的一个基本通信流程,概括一下Socket 一般应用模式(客户端和服务器端)的作用:

服务器端:最少有两个socket,一个是服务端负责监听客户端发来连接请求,但不负责与请求的客户端通信,另一个是每当服务器端成功接收到客户端时,但在服务器端创建一个用与请求的客户端进行通信的socket.

客户端:指定要连接的服务器端地址和端口,通过创建一个socket对象来初始化一个到服务器端的TCP连接。

      为我接下来要写的服务器的通信过程和插件调用做一个铺垫。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-14 20:27:16 | 显示全部楼层
正在下载VC++英文版,300多M,我先去工作室调一下,我的游戏脚本。回来继续执行。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-1-15 02:29:26 | 显示全部楼层
今天网络不稳定,游戏里的账号掉线了好多。真实辛苦的兼职。
继续执行编程:决定使用MFC实现我的软件。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-1-15 21:40:10 | 显示全部楼层
我不得不顶了…… 加油吧 ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-23 10:16

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表