码迷,mamicode.com
首页 > 其他好文 > 详细

15-03-16 Socket网络编程

时间:2015-03-16 22:57:40      阅读:277      评论:0      收藏:0      [点我收藏+]

标签:

socket套接字就是程序间的电话机;
协议:电脑与电脑或者应用程序与应用程序之间默认的语言;
客户端与服务器的某个应用程序连接, 要连接到服务器,首先要知道服务器的IP地址;但是仅仅知道IP地址不行,只知道IP
地址连接到的是服务器;服务器上这么多应用程序,他们的IP地址都是一样的;这个时候如果知道端口号,就可以连接到你想连接
的应用程序;所以说你要连接服务器上的某个应用程序,需要知道IP地址和端口号;
男生去女生宿舍找女生,中间有宿管大妈搁着,女生宿舍相当于服务器,男生相当于客户端,宿管大妈相当于负责监听的socket
女生相当于负责通信的socket;
客户端要连接服务器,首先要知道服务器端的IP地址;服务器上有很多应用程序,客户端是连接到服务器上的某个应用程序;这些
应用程序都在同一台服务器上,他们的IP地址是一样的,但是如何找到我要连接的应用程序呢,这时候就要找到我要连接的应用
程序的端口号;有了IP地址和端口号,这时候我们就能准确的连接到服务器上的应用程序;
Tcp协议安全稳定,一般不会发生数据丢失;TCP传输过程中,会经历三次过程,我们称之为三次握手;TCP协议要求我们必须有服务器;
这个请求是客户端发给服务器的,服务器不能给客户端发请求;因为服务器不知道客户端在哪里;
三次握手就像客户端发送给服务器 你有空吗? 服务器返回我有空, 然后客户端发送我知道你有空了;TCP只有在这三次握手成功后,
才和服务端收发数据;所以TCP好处是安全稳定,但是效率相对低;
UDP协议快速,效率高,但是不稳定,容易发生数据丢失;客户端给服务器发消息了,我不管你服务器有没有空,我就给你发;如果服务器
很忙的话,就没时间处理信息,造成数据丢失;没有好坏,各有各的优点;视频传输的时候用的是UDP;

==========================================================================================================================================//服务器
//模拟的是服务器和客户端之间的通信;下面这段是服务器端;服务器端干的第一件事是创建一个负责监听的Socket;监听的是本机应用程序的端口号;
但是端口号里也包含着本机应用程序的IP地址;监听的目的就是等待客户端的连接,客户端连接过来,我这个负责监听的socket就知道这个信息了,
当知道之后,就创建一个负责通信的Socket;负责通信的Socket是负责监听的Socket调用Accept();为什么要写在一个循环里面,因为我们服务端会有很多
客户端链接过来,应该是每一个客户端都为他创建一个负责通信的Socket;为什么写在一个函数里面让线程去执行呢;因为Accept会阻碍我们主线程的运行;
客户端如果一直不连接过来会卡死,因此我们创建一个新的线程去调用这个方法;函数当中需要用到负责监听的Socket,我们选择以参数的形式传进来,但是
被线程执行的函数如果有参数的话必须是object类型;因此在函数当中进行类型转换as,我们在调用的时候,传的是负责监听的Socket,Listen相当于进入公园
只有10扇门,想进去就要排队;


//当点击开始监听的时候,在服务器端创建一个负责监听IP地址和端口号的Socket
Socket SocketWatch = new Socket(AddressFamily.InterNetWork,SocketType.Stream,ProtocolType.Tcp)
) //0,创建一个负责监听的Socket
IPAddress ip = IPAddress.Any; //IPAddress.Parse(txtServer.Text);
//创建端口号对象;
IPEndPoint point = new IPEndPoint(ip,Convert.ToInt32(TextPort.Text)); //端口号中同样有我们的IP地址;
//监听
SocketWatch.Bind(point); //1.绑定监听端口;
ShowMsg("监听成功");

 

//服务器在一个点内能接纳的客户端是有上限的,这个上限不是指服务器的容量问题;指的是在一秒内能连接的数量;
SocketWatch.Listen(10); //一个时间点内能接纳的人数为10个人;第十一个人来了排队;  //2.设置监听队列;
如果一个服务器最多容纳20000人,怎么增加数量,最好的办法就是加服务器;百度服务器多,全中国都有,连最近的那个服务器;
-----------------------------------------Socket SocketSend = SocketWatch.Accept(); //3.他能接收客户端的连接,并创建负责通信的Socket; //等待客户端连接,如果客户端一直不连的话会死

掉,解决办法创建一个新线程
-----------------------------------------//如果单单这样写的话只能连接一个人;解决2个问题,1假死(创建线程) 2只能连一个客户端(写一个While循环)
-----------------------------------------ShowMsg(SocketSend.RemoteEndPoint.ToString()); //通过负责通信的Socket可以获得远程客户端的IP和端口号,IP在端口号内;192.168.11.87:29990
----------------------------------------- //telnet是本地连接的一个服务器; 控制面板,程序和功能;启用或关闭windows功能;把Telnet服务器和Telnet客户端打上勾,我们通过Telnet去连接服务

器;
Thread th = new Thread(Listen);
th.IsBackground;
th.Start(SocketWatch);

 

 

 

void ShowMsg(string str)
{
  txtLog.AppendText(str + "\r\n");(追加的意思,在每行结束的时候换行);
}

 


Socket SocketSend;
void Listen(Object o)   //这个方法最终要被新线程执行,线程所执行的函数,如果有参数,必须是object类型
{
   Socket SocketWatch = o as Socket;
 try{
   while(true)
{
   SocketSend = SocketWatch.Accept(); //负责监听的Socket只干了这件事,剩下的与客户端通信都与负责通信的Socket来做;//一旦来一个新的用户,原来的那个负责通信的Socket就没了,导致服务

端只能给最后一个连接的客户端发送信息; 跟哪个客户端通信取决于拿到的是哪个Socket;IP地址不能发消息,得是IP地址对应的Socket才能发;
   dicSocket.Add(SocketSend.RemoteEndPoint.ToString(),SocketSend); //拿到远程客户端的IP和其对应的Socket对象;
   CboUsers.Items.Add(SocketSend.RemoteEndPoint.ToString());将远程客户端的IP存储到下拉框中;
   ShowMsg(SocketSend.RemoteEndPoint.ToString()+ ":连接成功");
   //客户端连接过来之后,我们就要接受客户端发送过来的消息;

 

   //由于下面这几句代码只执行一遍,因此无法连续发送字符串,解决办法写一个while循环,但是while循环又会导致程序假死
   因此再创建一个线程,去执行这个方法;  

-------------------------------------------------------------------------------   byte[] buffer = new byte[1024*1024*2];
-------------------------------------------------------------------------------   //实际接收到的有效的字节数;
-------------------------------------------------------------------------------   int r = SocketSend.Receive(buffer);
-------------------------------------------------------------------------------   //这就是客户端发送过来的字符串,我们把它显示在文本框里
-------------------------------------------------------------------------------   string str = Encoding.UTF8.GetString(buffer,0,r);
-------------------------------------------------------------------------------   ShowMsg(SocketSend.RemoteEndPoint + ":" + str;
    //开启一个新线程不停的接收客户端发送过来的消息
    Thread th = new Thread(Receive);
    th.IsBackground = true;
    th.Start(SocketSend);
   }
   catch
   {

    } 
 }
}


在FormLoad事件里
Control.CheckForIllegalCrossThreadCalls = false;

//这段就是服务器不停的接收客户端发来的消息;
void Receive(object o)
{
    Socket SocketSend = o as Socket;
try
 {
    while(true)
    {
        byte[] buffer = new byte[1024*1024*2];
        //实际接收到的有效的字节数;
        int r = SocketSend.Receive(buffer);
        if(r == 0)
        {
          break;  //如果关闭客户端接收到的就是空消息,注意,空消息和空格是不一样的,在线的话发不出空消息
         }
        //这就是客户端发送过来的字符串,我们把它显示在文本框里
        string str = Encoding.UTF8.GetString(buffer,0,r);
        ShowMsg(SocketSend.RemoteEndPoint + ":" + str;
    }
  }
 catch
  {
     //不写的话,就算出现异常也不会显示给用户;给用户的感觉就是什么都没异常;
    }
   
}

凡是操作网络的东西,肯定会引发各种各样的异常;因此要try catch,微软在写源代码的时候用了大量的try catch


//服务器端给客户端发送消息
string str = txtMsg.Text;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);

//为了区分是文本,文件,震动,在字节数组buffer前面加一个数字0,表示文本, 1表示文件,2表示震动
//声明一个长度为buffer.length+1的数组,buffer[0] = 0;然后一个循环赋值后面的;方法1
//方法2用泛型集合
List<byte> list = new List<byte>();
list.Add(0);
list.AddRange(buffer);
//将泛型集合转化为数组
byte[] newbuffer = list.ToArray();


//获得用户在下拉框选中的IP地址;
string ip = CboUsers.SelectItem.ToString();
dicSocket[ip].Send(newbuffer);
//socketSend.Send(buffer);

 

 

//将远程连接的客户端的IP地址和对应的Socket联系起来;用键值对存储;
Dictionary<string,Socket> dicSocket = new Dictionary<string,Socket>();

 


//为了区分服务端发送给客户端的是文本,文件,还是震动;我们就在传送的字节数组的最前面加上一个数字来判断;0表示文本,1表示文件,2表示震动;


//在选择发送文件的按钮里
openfileDialog ofd = new openfileDialog();
ofd.InitialDirectory = @"桌面路径";
ofd.Title = "请选择要发送的文件";
ofd.Filter = "所有文件|*.*";
ofd.ShowDialog();
TxtPath.Text = ofd.FileName;

 

//当点击发送按钮的时候,把文件发送过去;//发送大文件比这个要麻烦,因为涉及到断点续传的问题;发的时候要把大文件切割成小文件;
//获得要发送文件的路径
string path = txtPath.Text;
using(FileStream fsRead = new FileStream(path,FileMode.open,FileAccess.Read))
{
   byte[] buffer = new byte[1024 * 1024 * 5];
   int r = fsRead.Read(buffer,0,buffer,length);
   List<byte> list = new List<byte>();
   list.Add(1);
   list.AddRange(buffer);
   byte[] newbuffer = list.ToArray();
   dicSocket[cboUsers.SelectedItem.Tostring()].Send(newbuffer,0,r+1,SocketFlags.None);
   
  
}


当点击震动按钮的时候
  byte[] buffer = new byte[1];
  buffer[0] = 2;
  dicSocket[cboUsers.SelectedItem.Tostring()].Send(buffer);
 
 

============================================================================================================================//客户端
Socket SocketSend;
//客户端不需要负责监听的Socket
try
{
    SocketSend = new Socket(AddressFamily.InterNetWork,SocketType.Stream,ProtocolType.Tcp);
    IPAddress ip = IPAddress.Parse(txtServer.Text);
    IPEndPoint point = new IPEndPoint(ip,Convert.ToInt32(txtPort.Text));
    //获得要连接的远程服务器应用程序的IP地址和端口号;
    SocketSend.Connect(point);
    ShowMsg("连接成功");
    //开启一个新的线程,不停地接收服务端发来的消息
    Thread th = new Thread(Receive);
    th.IsBackground = true;
    th.Start();
}
catch
{
  
}

 

 

void ShowMsg(string str)
{
   txtLog.AppendText(str + "\r\n");
}

 


//先开启服务器监听,在客户端连接;
winform开启第二个项目,右键项目,调试,启动新实例;


//客户端发送信息到服务器
string str = TextMsg.Text.Trim();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
SocketSend.Send(buffer);
 


//不停接收客户端接收服务端的消息
void Receive()
{
   while(true)
   {
     try
      {
       byte[] buffer = new byte[1024*1024*2];
         //实际接收到的有效字节数;
  int r = socketSend.Receive(buffer);
          if(r == 0)
           {
               break;    //因为还有两个buffer[0] ==1 ==2也要用到这个,干脆写到外面了
           }
       //这里要判断字节数组的第一位
       if(buffer[0] == 0)   //表示发送的是文字消息
         {           
            
           //由于包含前面那个0 因此这句话要改为 string s = Encoding.UTF8.GetString(buffer,0,r);
            string s = Encoding.UTF8.GetString(buffer,1,r - 1);
            ShowMsg(SocketSend.RemoteEndPoint + "" + s);
          }
      if(buffer[0] == 1)                                   //缺陷是发送的.txt还是.jpg还是其他类型的文件不知道,解决办法是第一位后也创建一个协议,
          {
             SavaFileDialog sfd = new SavaFileDialog();
             sfd.InitialDirectory = @"桌面路径";
             sfd.Title = "请选择要保存的文件";
             sfd.Filter = "所有文件|*.*";
             sfd.ShowDialog(this);
             string path = sfd.FileName;
             using(FileStream fsWrite = new FileStream(path,FileMode.OpenOrCreate,FileAccess.Write))
              {
                 fsWrite.Write(buffer,1,r-1);
               }
               MessageBox.Show("保存成功");
           }
         if(buffer[0] == 2)
          {
            ZD();
           }      
       }
     catch
       {

        }
    }
}


void ZD()
{
  for(int i = 0;i<=500;i++)
   {
     this.Location = new Point(200,200);
     this.Location = new Point(280,280);
    }
}

 

在FormLoad事件里
Contral.CheckForIllegalCrossThreadCalls = false;

==================================================================================
客户端                                    服务端
Socket()                                  Socket()
                                          Bind() 绑定监听窗口
                                          Listen() 设置监听队列
                                          while(true)
                                         {
Connect()---------建立连接--------         Accept()   //循环等待客户端连接
                                         }
Send()                                    Receive()
Receive()                                 Send()
Close()                                   捕捉异常 Close()

15-03-16 Socket网络编程

标签:

原文地址:http://www.cnblogs.com/hhsfrank/p/4342912.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!