您的位置:首页 > 编程语言

socket编程基础-原理和代码

2013-03-29 17:38 375 查看
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);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: