Socket 编程

分3个部分,首先介绍Socket基本概念(主要参考《Socket编程》);然后分别是基于MFC的Socket编程(参考《MFC socket网络编程(流程示例)》)和基于C#的Socket编程(参考《你得学会并且学得会的Socket编程基础知识》


Socket是什么

如图1所示,传输控制协议/网间协议(TCP/IP)是一个工业标准的协议集,包含了运输层、网络层、链路层

Socket 是应用层与TCP/IP协议族通信的中间软件抽象层,将复杂的TCP/IP隐藏在一系列Socket接口后面

         这里写图片描述
                        图1. Scoket抽象层

一次标准的Socket通信为(图2):
服务端首先初始化Socket,然后绑定并监听端口,阻塞直到有客户端连接,接着使用send和receive方法与客户端交互,最后关闭Socket;
客户端首先初始化Socket,然后根据Ip和端口与服务端连接,成功后通过send和receive方法与之交互,最后关闭Socket

           这里写图片描述
                       图2. Socket通信


基于MFC的Socket编程

首先添加链接库:ws2_32.lib

服务端

  1. 加载套接字(socket)库
  2. 创建套接字
  3. 绑定套接字到本地地址和端口
  4. 将套接字设为监听模式
  5. 等待客户请求到来,当请求到来后接受并返回此次连接的套接字
  6. 使用上一步的套接字和客户端通信(send/recv)
  7. 关闭套接字
#include <Winsock2.h>//加裁头文件 
#include <stdio.h>//加载标准输入输出头文件 
void main()
{ 
    WORD wVersionRequested;//版本号 
    WSADATA wsaData; 
    int err; 
    wVersionRequested = MAKEWORD( 1, 1 );//1.1版本的套接字 
    err = WSAStartup( wVersionRequested, &wsaData ); 
    if ( err != 0 ) { return; }//加载套接字库,加裁失败则返回 
    if ( LOBYTE( wsaData.wVersion ) != 1 ||HIBYTE( wsaData.wVersion ) != 1 ) 
    { 
        WSACleanup( );
        return; 
    }//如果不是1.1的则退出 

    SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);//创建套接字(socket)。 
    SOCKADDR_IN addrSrv; 
    addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//转换Unsigned short为网络字节序的格式   
    addrSrv.sin_family=AF_INET; 
    addrSrv.sin_port=htons(6000); 
    bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); //将套接字绑定到一个本地地址和端口上(bind) 
    listen(sockSrv,5);//将套接字设为监听模式,准备接收客户请求(listen)。 

    SOCKADDR_IN addrClient;//定义地址族 
    int len=sizeof(SOCKADDR);//初始化这个参数,这个参数必须被初始化 
    while(1) 
    { 
        SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len); //accept的第三个参数一定要有初始值。 //等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)。 //此时程序在此发生阻塞 
        char sendBuf[100]; 
        sprintf(sendBuf,"Welcome %s to www.msn.com.cn",inet_ntoa(addrClient.sin_addr)); //用返回的套接字和客户端进行通信(send/recv)。 
        send(sockConn,sendBuf,strlen(sendBuf)+1,0); 
        char recvBuf[100]; 
        recv(sockConn,recvBuf,100,0); 
        printf("%s\n",recvBuf); 
        closesocket(sockConn);//关闭套接字。等待另一个用户请求 
    } 
}

客户端

  1. 加载套接字库
  2. 创建套接字
  3. 向服务器发出连接请求
  4. 和服务器进行通信(send/recv)
  5. 关闭套接字
#include <Winsock2.h> 
#include <stdio.h> 
void main() 
{ 
    WORD wVersionRequested; 
    WSADATA wsaData; 
    int err; 
    wVersionRequested = MAKEWORD( 1, 1 ); 
    err = WSAStartup( wVersionRequested, &wsaData );//加载套接字库 
    if ( err != 0 ) { return; } 
    if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) 
    { 
        WSACleanup( ); 
        return; 
    } 

    SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);//创建套接字(socket)。 
    SOCKADDR_IN addrSrv; 
    addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); 
    addrSrv.sin_family=AF_INET; 
    addrSrv.sin_port=htons(6000); 
    connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//向服务器发出连接请求(connect)。 

    char recvBuf[100];//和服务器端进行通信(send/recv)。 
    recv(sockClient,recvBuf,100,0); 
    printf("%s\n",recvBuf); 
    send(sockClient,"This is blues_j",strlen("This is blues_j")+1,0); 
    closesocket(sockClient);//关闭套接字。 
    WSACleanup();//必须调用这个函数清除参数 
}

基于C#的Socket编程

服务端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net.Sockets;
using System.Net;

namespace socket_server
{
    class Program
    {
        static IPAddress[] ServerIp;
        static int port = 6000;
        static void Main(string[] args)
        {
            // 基于TCP的Stream Scoket
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            // 绑定端口
            ServerIp = Dns.GetHostAddresses("");
            socket.Bind(new IPEndPoint(ServerIp[2], port));
            // 开始监听,设定最大队列长度
            socket.Listen(4);

            // 接受客户端连接请求
            socket.BeginAccept(new AsyncCallback((ar) =>
            {
                var client = socket.EndAccept(ar);
                client.Send(Encoding.Unicode.GetBytes("Accept your request at " + DateTime.Now.ToString()));

                //定时器
                var timer = new System.Timers.Timer();
                timer.Interval = 2000D;
                timer.Enabled = true;
                timer.Elapsed += (o, a) =>
                { 
                    //检测客户端连接状态
                    if (client.Connected)
                    {
                        try
                        {
                            //Console.WriteLine("Heart Beat " + DateTime.Now.ToString());
                            ;
                        }
                        catch (SocketException ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                    else
                    {
                        timer.Stop();
                        timer.Enabled = false;
                        Console.WriteLine("Client is disconnectd");
                    }
                };
                timer.Start();

                //接收客户端消息
                client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), client);

            }), null);


            Console.WriteLine("[" + ServerIp[2].ToString() + ":" + port.ToString() + "]" + "Server is ready!");
            Console.Read();
        }

        static byte[] buffer = new byte[1024];

        public static void ReceiveMessage(IAsyncResult ar)
        {
            try
            {
                var socket = ar.AsyncState as Socket;
                var length = socket.EndReceive(ar);
                //var message = Encoding.Unicode.GetString(buffer, 0, length);
                var message = Encoding.UTF8.GetString(buffer, 0, length);
                Console.WriteLine("[" + socket.RemoteEndPoint.ToString() + "]" + message);
                socket.Send(Encoding.UTF8.GetBytes("[" + ServerIp[2].ToString() + ":" + port.ToString() + "]" + "Hey this is a response from server " + DateTime.Now.ToString() + '\0'));

                socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket);
            }
            catch (Exception ex){
                Console.WriteLine(ex.Message);
            }
        }
    }
}

客户端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net.Sockets;

namespace SocketClient
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建一个Socket
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //连接到指定服务器的指定端口
            socket.Connect("localhost", 6000);
            Console.WriteLine("connect to the server");

            //实现接受消息的方法

            socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket);

            //接受用户输入,将消息发送给服务器端
            while(true)
            {
                var message = "Message from client : " + Console.ReadLine();
                var outputBuffer = Encoding.Unicode.GetBytes(message);
                socket.BeginSend(outputBuffer, 0, outputBuffer.Length, SocketFlags.None, null, null);
            }

        }


        static byte[] buffer = new byte[1024];

        public static void ReceiveMessage(IAsyncResult ar)
        {
            try
            {
                var socket = ar.AsyncState as Socket;

                var length = socket.EndReceive(ar);
                //读取出来消息内容
                var message = Encoding.Unicode.GetString(buffer, 0, length);
                //显示消息
                Console.WriteLine(message);

                //递归接收下一个消息
                socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值