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

孙鑫 第十四课Socket编程之一 简介

2012-12-05 17:19 316 查看
1 Socket编程分为基于TCP的和基于UDP的
TCP:面向连接的,可靠的传输,连接要经过三次握手,客户端在连接之前就得按照已知的服务器地址 端口进行连接,服务器端在等到客户端的连接后返回一个连接套接字,之后的信息发送接收就按这条连接进行,不需要再有地址信息。
UDP:面向无连接的,不可靠的,不会进行重发,由于没有连接,因此每次发送都要指明对方的IP 端口,每次接收都要信息的同时要接收对方地址 端口。
在socket编程中,套接字有三种,流式套接字(SOCK_STREAM), 数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW),基于TCP的采用的是流式套接字,基于UDP的采用的是数据报套接字,socket2.0版本不支持原是套接字。

2 基于TCP的套接字编程
★ 基于TCP的服务器端套接字编程步骤
①协商版本 / 初始化(WSAStartup)
②建立服务器套接字(socket)
③套接字绑定本机IP 和 端口(bind)
④设置为监听模式(listen)
⑤开始监听连接,如果有连接到来则返回一个连接套接字(同时取得客户端地址 端口),否则一直在此监听。(accept)
⑥使用连接套接字开始和客户端通信(发送 / 接收)。(send / recv)
⑦通信完毕,关闭套接字(连接套接字 / 服务器套接字)。(closesoket)
⑧释放资源,删除套接字库的使用。(WSACleanup)

★ 基于TCP的客户端套接字编程步骤
①协商版本 / 初始化 (WSAStartup)
②建立客户端套接字 (socket)
③指定服务器地址 / 端口。(SOCKADDR_IN addrServer)
④连接服务器(connect)
⑤开始通信(发送 / 接收)。(send / recv)
⑥通信完毕,关闭套接字。(closesoket)
⑦释放资源,删除套接字库的使用。(WSACleanup)

NOTE
基于TCP的socket编程中服务器端和客户端的区别:
①客户端不用绑定本地IP 和 端口。
②由于服务器是被动的等待连接,因此必须先由客户端发起连接请求(这样服务器才能知道客户端的地址 端口),而客户端在连接服务器之前就应该已经知道了服务器地址。

3 基于UDP的套接字编程
★ 基于UPD的服务器端套接字编程步骤
①协商版本 / 初始化(WSAStartup)
②建立套接字(socket)
③绑定本地IP 端口(bind)
④通信, 发送 / 接收 (sendto / recvfrom)
⑤通信完毕,关闭套接字(closesocket)
⑥释放资源,删除使用套接字库(WSACleanup)

★ 基于UDP的客户端套接字变成步骤
①协商版本 / 初始化(WSAStartup)
②建立套接字 (socket)
③通信,发送 / 接收(sendto / recvfrom)
④通信完毕,关闭套接字(closesoket)
⑤释放资源,删除使用套接字库(WSACleanup)

NOTE:
基于UDP的客户端编程中客户端不必发起连接请求,为了能达到服务器,需要在sendto函数中指定地址端口。
服务器段也需要在sendto函数中指定客户端的地址端口。
而在基于TCP的服务器中,在返回连接套接字后,已经和对方建立了连接,也就是说早accept函数中取得了客户端的地址。
基于TCP的客户端中,在发起连接请求的时候要指定服务器的地址和端口,因此连接建立以后的send / recv 都不再需要地址端口。

4 TCP实例
下面是孙鑫老师视频中讲的一个基于TCP的socket编程例子(稍有改动),提供了socekt TCP编程的基本思路。
////////////////////////////////////////////服务器端////////////////////////////////////////////////////////
#include <WinSock2.h> //必须的头文件
#include <iostream>
#include "stdio.h"
#pragma comment(lib, "ws2_32.lib") //指定连接的库文件,取代在VC工程设置里添加
using namespace std;
int main()
{
WORD wVersionRequested;//版本号
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );//1.1版本的套接字, 协商版本 初始化
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) //加载套接字库,加裁失败则返回
{
cerr<<"startup error!"<<endl;
return -1;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||HIBYTE( wsaData.wVersion ) != 1 ) //如果不是1.1的则退出
{
WSACleanup( );
cerr<<"version error!"<<endl;
return -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_addr.s_addr = inet_addr("127.0.0.1"); //同上句,假如只有一块网卡
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 tohttp://www.sunxin.org",inet_ntoa(addrClient.sin_addr));//用返回的套接字和客户端 // 进行通信(send / to)
send(sockConn,sendBuf,strlen(sendBuf)+1,0);
char recvBuf[100];
recv(sockConn,recvBuf,100,0);
printf("%s\n",recvBuf);
closesocket(sockConn);//关闭套接字。等待另一个用户请求
}
closesocket(sockSrv); //关闭服务器套接字
WSACleanup(); //释放资源
return 0;
}

////////////////////////////////////////////客户端////////////////////////////////////////////////////////
#include <Winsock2.h>
#include <stdio.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib") //加载库
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData ); //初始化, 协商版本
if ( err != 0 )
{
cerr<<"startup error!"<<endl;
return -1;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||HIBYTE( wsaData.wVersion ) != 1 )
{
WSACleanup( );
cerr<<"version error!"<<endl;
return -1;
}
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_addr.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 lisi",strlen("This is lisi")+1,0);
closesocket(sockClient); //关闭套接字。
WSACleanup();//必须调用这个函数清除参数
}
return 0;
}

5 基于UDP的套接字编程实例
////////////////////////////////////服务器端//////////////////////////////////////////////////////////////////
#include <iostream>
#pargma comment(lib, "ws2_32.lib")
using namespace std;
#define LOW_VERSION 2
#define HIGH_VERSION 0
#define PORT 6000

int main()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequsted = MAKEWORD(LOW_VERSION, HIGH_VERSION);
if( 0 != WSAStartup(wVersionRequsted, &wsaData);
{
cerr<<"startup error!"<<endl;
WSACleanup();
return -1;
}
if(LOBYTE(wsaData.wVersion) != LOW_VERSION || HIBYTE(wsaData.wVersion) != HI_VERSION)
{
cerr<<"version error!"<<endl;
WSACleanup();
return -1;
}
SOCKET sockServer = socket(AF_INET, SOCK_DGRAM, 0); // 建立服务器套接字
SOCKADDR_IN addr_server; //服务器地址端口结构体
char* ip = "127.0.0.1";
addr_server.sin_addr.s_addr = inet_addr(ip);
addr_server.sin_family = AF_INET;
addr_server.sin_port = htons(PORT);
bind(sockServer, (SOCKADDR*) &addr_server, sizeof(SOCKADDR));

char recvBuffer[100];
memset(recvBuffer, '\0', sizeof(recvBuffer) );
char sendBuffer[100] = "hello client!";

SOCKADDR_IN addr_client;
int len = sizeof(SOCKADDR);
while(1)
{
//服务器执行到recvfrom发生阻塞,一直在此监听信息到达,接收信息的同时接收到对方IP 和 端口
recvfrom(sockServer, recvBuffer, sizeof(recvbuffer), 0, (SOCKADDR*) &addr_client, &len); //最后一个参数一定要初始 //化
sendto(sockServer, sendBuffer, strlen(sendBuffer) + 1, 0, (SOCKADDR*) &addr_client, sizeof(SOCKADDR));
//codes
}
closesocket(sockServer);
WSACleanup();
return 0;
}

//////////////////////////////////////////////客户端/////////////////////////////////////////////////////////////

#include <iostream>
#pargma comment(lib, "ws2_32.lib")
using namespace std;
#define LOW_VERSION 2
#define HIGH_VERSION 0
#define PORT 6000

int main()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequsted = MAKEWORD(LOW_VERSION, HIGH_VERSION);
if( 0 != WSAStartup(wVersionRequsted, &wsaData);
{
cerr<<"startup error!"<<endl;
WSACleanup();
return -1;
}
if(LOBYTE(wsaData.wVersion) != LOW_VERSION || HIBYTE(wsaData.wVersion) != HI_VERSION)
{
cerr<<"version error!"<<endl;
WSACleanup();
return -1;
}
SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0);

SOCKADDR_IN addr_server; //服务器地址端口结构体
char* ip = "127.0.0.1";
addr_server.sin_addr.s_addr = inet_addr(ip);
addr_server.sin_family = AF_INET;
addr_server.sin_port = htons(PORT);
int len = sizeof(SOCKADDR);

char recvBuffer[100];
memset(recvBuffer, '\0', sizeof(recvBuffer) );
char sendBuffer[100] = "hello server!";

while(1)
{
sendto(sockClient, sendBuffer, strlen(sendBuffer) + 1, 0, (SOCKADDR*) &addr_server, sizeof(SOCKADDR));
recvfrom(sockClient, recvBuffer, sizeof(recvBuffer), 0, (SOCKADDR*) &addr_server, &len);
//codes
}
closesocket(sockClient);
WSACleanup();
return 0;
}

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