socket编程基础-原理和代码

http://blog.csdn.net/markmin214/article/details/8734812

socket是连接运行在网络上得两个程序间的双向通讯的端点,在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原意那样,象一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电,有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。

    一个完整的网络通信需要一个五元组来标识:协议、本地地址、本地端口号、远端地址、远端端口号。完整的网间通信进程需要由两个进程组成,并且只能用同一种高层协议。也就是说,不可能通信的一端用TCP,而另一端用UDP

Socket通信的两种模式

  面向连接的

    面向连接的socket操作就像一部电话,他们必须建立一个连接,并由一人呼叫。所有的事情在到达时的顺序与它们出发时的顺序是一样的。面向连接的操作使用TCP协议.这个模式下的socket必须在发送数据之前与目的地的socket取得一个连接.一旦连接建立了,socket就可以使用一个流接口:打开-读-写-关闭.所有的发送的信息都会在另一端以同样的顺序被接收.面向连接的操作比无连接的操作效率低,但是数据的安全性更高.

      TCP是Transfer  ControlProtocol的简称,是一种面向连接的保证可靠的传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接受方的,成对的两个Socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个Socket(通常是Serversocket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或操作。因为要安全可靠相对的要付出一定代价,传输效率不如UDP高。 

                 


无连接的

    无连接的socket操作就像是一个邮件投递,,没有什么保证,多个邮件可能在到达时的顺序与出发时的顺序不一样。无连接的操作使用数据报(UDP)协议.一个数据报是一个独立的单元,它包含了所有的这次投递的信息.把它想象成一个信封吧,它有目的地址和要发送的内容这个模式下的socket不需要连接一个目的地socket,它只是简单地投出数据报.无连接的操作是快速的和高效的,但是数据安全性不佳.

     UDP是User DatagramProtocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。这样的特性决定了那些不要求音频视频数据绝对正确,只要保证连贯性即可的场合。

                

端口与地址

在网络上,一个Socket的标识主要借助于地址和端口来描述。

     地址指该套接字所在计算机的网络地址,可以为域名或IP地址的形式。同一机器上可以运行多个网络应用程序,每个应用程序都有自己的套接字用以进行网络通信,此时如果只有地址标识套接字,则当一个通信包到达机器时,将无法确定究竟是哪个应用程序的套接字需要接收此信息。由此增加了端口的概念,以协助区分同一机器上不同应用程序的套接字

     端口用于标识进程,同一机器上不同的网络应用程序各有不同的端口,这样,通过“网络地址+端口号”的标识方法,便唯一标识了机器上的应用程序了。某些端口是专门为公共服务保留的(Ftp:21,http:80),除非程序是要提供这些服务,否则应尽量避免使用这些端口。端口1024以前的端口号都是系统保留的或是作为公共服务的,应尽量选择大于1024的端口号,以避免冲突。

Socket通信过程

1.服务器程序将一个套接字绑定到一个特定的端口,并通过此套接字等待和监听客户端的连接请求。

2.客户程序根据服务器程序所在的主机名和端口号发出连接请求

3.如果一切正常,服务器接受连接请求,并获得一个新的绑定到不同端口地址的套接字

4.客户端和服务器端通过读、写套接字进行通讯。

网络连接函数

socket 创建套接字

bind 绑定本机端口

connect 建立连接

listen 监听端口

accept 接受连接

recv, recvfrom 数据接收

send, sendto 数据发送

close, shutdown 关闭套接字

SOCKET socket(

int af,//地址族,一般是AF_INET,表示使用IP地址族

int type,//socket类型,SOCK_STREAM或SOCK_DGRAM

int protocol//协议类型,通常取值0

);

Winsock中使用sockaddr_in结构指定IP地址和端口信息

struct sockaddr_in{

short  sin_family;

u_short  sin_port;

struct in_addrsin_addr;

char sin_zero[8];

}

sin_family一般为AF_INET,表示使用IP地址族;sin_port是以网络字节序表示的16位端口号;sin_addr是网络字节序的32位IP地址;sin_zero字段一般不用,用0填充

int connect(

SOCKET s,//将要连接的socket

const structsockaddr FAR * name, //目标socket地址

int namelen//地址参数(name)的长度

);

int send(

SOCKET s,

const char FAR * buf,//发送数据缓冲区

int len, //缓冲区长度

int flags//用于控制数据传输方式,0表示按正常方式发送数据

);

返回值:发送的字节数

int recv(

SOCKET s,

char FAR * buf,//接收数据缓冲区

int len, //缓冲区长度

int flags //0表示接收的是正常数据,无特殊行为

);

返回值:接收到的字节数

int WSAStartup(

WORD wVersionRequested,

LPWSADATA lpWSAData

);

wVersionRequested是一个WORD型(双字节型)数值,指定使用的版本号,对Winsock2.2而言,此参数的值为0x0202,也可以用宏MAKEWORD(2,2)来获得

lpWSAData是一个指向WSADATA结构的指针,它返回关于Winsock实现的详细信息

#include<Winsock2.h>

#include<stdio.h>

//需要在Project->Settings->Link->Object/librarymodules中加入ws2_32.lib

void main()

{

WORD wVersionRequested;

WSADATA wsaData;

wVersionRequested=MAKEWORD(2,2);

if(WSAStartup(wVersionRequested,&wsaData)!=0)//初始化ws2_32.dll动态库

{

printf("WSAStartup()failed!\n");//Winsock初始化错误

exit(-1);

}

if(wsaData.wVersion!=wVersionRequested)

{

printf("Theversion of Winsock is not suited!\n");//Winsock版本不匹配

WSACleanup();//结束对ws2_32.dll的调用

exit(-1);

}

//说明ws2_32.dll正确加载

printf("Loadws2_32.dll successfully!\n");

}

  代码

#include<windows.h>

#include<windowsx.h>

#include"main.h"

#include"dialogs.h"

#include"resource.h"

#include"winsock2.h"

BOOL WINAPIMain_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

    switch(uMsg)

    {

        /* BEGIN MESSAGE CRACK */

        HANDLE_MSG(hWnd, WM_INITDIALOG,Main_OnInitDialog);

        HANDLE_MSG(hWnd, WM_COMMAND,Main_OnCommand);

        HANDLE_MSG(hWnd,WM_CLOSE,Main_OnClose);

        /* END MESSAGE CRACK */

    }

    return FALSE;

}

/*******************************************************************************

*  Main_OnInitDialog

*/

BOOLMain_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)

{

    /* Set app icons */

    HICON hIcon = LoadIcon((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE) ,MAKEINTRESOURCE(IDI_ICONAPP));

    SendMessage(hwnd, WM_SETICON, TRUE,  (LPARAM)hIcon);

    SendMessage(hwnd, WM_SETICON, FALSE,(LPARAM)hIcon);

   

    /*

    * Add initializing code here

    */

   

    return TRUE;

}

/*******************************************************************************

*  Main_OnCommand

*/

voidMain_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)

{

    switch(id)

    {

        case IDC_OK:

            SocketTest(hwnd);

        break;

        case IDC_CANCEL:

            MessageBox(hwnd,TEXT("Youclicked Cancel!"),TEXT("socket"),MB_OK);

            EndDialog(hwnd, id);

        break;

        default:break;

    }

}

/*******************************************************************************

*  Main_OnClose

*/

void Main_OnClose(HWNDhwnd)

{

    EndDialog(hwnd, 0);

}

void SocketTest(HWNDhwnd)

{

WSADATAwsaData;

WSAStartup(MAKEWORD(2,0),&wsaData);    //初始化socket

//创建socket

SOCKETsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

SOCKADDR_IN  sa;

sa.sin_family= AF_INET;

sa.sin_port= htons(IPPORT_SMTP);

sa.sin_addr.S_un.S_addr= inet_addr("123.125.50.138");

if(  connect(sock, (SOCKADDR *)&sa,sizeof(sa)) == SOCKET_ERROR)

{

ShowError();

return;

}

char buffer[256];

ZeroMemory(buffer,sizeof(buffer)/sizeof(char));

recv(sock,buffer,256,0);

MessageBox(hwnd,buffer,"",0);

char sBuffer[]="QUIT\n";

send(sock,sBuffer,lstrlen(sBuffer),0);

ZeroMemory(buffer,sizeof(buffer)/sizeof(char));

recv(sock,buffer,256,0);

MessageBox(hwnd,buffer,"",0);

closesocket(sock);

WSACleanup();

}

void ShowError()

{       

TCHAR*IpMsgBuf;

FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,

              NULL,GetLastError(),

             MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),

              (LPTSTR)&IpMsgBuf,

              0,

             NULL        );

   MessageBox(NULL,IpMsgBuf,"",MB_ICONERROR);

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值