套接字(二):Socket 套接字编程(附实例)

TCP/IP地址家族统一的套接字地址结构定义如下:
struct sockaddr_in
{
    short                         sin_family;        //指定地址家族,即地址格式
    unsigned short        sin_port;            //端口号码
    struct in_addr           sin_addr;           //IP地址
    char                           sin_zero[8];       //需要指定为0
}

 sin_family 指定使用该套接字地址的地址家族。 这里必须设置为AF_INET,表示程序所使用的地址家族是TCP/IP;
sin_zero[8] 主要是为了与第一个版本的套接字地址结构大小相同而设置,实际使用时,将这8个字节设置为0即可。

sin_addr 表示32为的IP地址结构 结构定义如下:
struct in_addr
{
    union
    {
        struct
        {
            u_char s_b1,s_b2,s_b3,s_b4;
        } S_un_b; //用4个u_char字符描述IP地址
        struct
        {
            u_short s_w1,s_w2;
        } S_un_w; //用2个u_short类型描述IP地址
       u_long S_addr;//用1个u_long类型描述IP地址
    } S_un;
#define s_addr S_un.S_addr
};

通常,使用一个u_long类型的字符进行描述IP地址即可。
sockaddr_in addr;
addr.sin_addr.S_un.S_addr = inet_addr("218.6.132.5");


 Socket 套接字编程中,传输数据的排列顺序以网络字节顺序和主机字节顺序为主。
数据在主机存储时,是以主机字节顺序存储的。
数据要通过网络发送,需要转换为网络字节顺序。否则会造成损坏。
网络字节是将重要的字节优先存储,而主机字节顺序则相反。

Winsock 中的网络字节和主机字节的转换函数
主机字节->网络字节
u_short htons(u_short hostshort); //u_short 类型的IP地址
u_long htonl(u_long hostlong); //u_long
unsigned long inet_addr(const char FAR* cp);//字符串IP
网络字节->主机字节
u_long ntohl(u_long hostlong);//u_long
u_short ntols(u_short hostshort);//u_short
char FAR* inet_ntoa(struct in_addr in);//字符串IP

具体使用:
sockaddr_in addrTo;
 addrTo.sin_family=AF_INET;
 addrTo.sin_port=htons(8900);
 addrTo.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
 
 char address[] = inet_ntoa(addrTo.sin_addr.S_un.S_addr);


Socket 相关函数
1.创建套接字
CSocket 类创建套接字是通过其构造函数创建的
CSocket :: CSocket();

创建CSocket对象
CSocket sock;
 CSocket *sock;
 sock = new CSocket;
2.绑定地址信息
如果套接字对象是服务器套接字,那么该套接字应该调用该类的函数Bind()将套接字对象与服务器地址信息绑定在一起。
BOOL Bind(const SOCKADDR* lpSockAddr,int nSockAddrLen);
    lpSockAddr 地址结构
    nSockAddrLen 地址结构长度

地址绑定成功后,还要调用函数Listen()在指定端口监听客户端的连接请求。 函数Listen()的原型如下:
BOOL Listen(int nConnectionBackLog = 5);
nContectionBackLog 表示套接字监听客户请求的最大数目。有效范围1~5。

具体调用
    CSocket sock;
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(80);
    addr.sin_addr.S_un.s_addr = inet_addr("127.0.0.1");
    sock.Bind((SOCKADDR*)addr,sizeof(addr)); //绑定套接字的地址结构
    sock.Listen(5);

3.连接服务器
    客户端创建套接字成功后,调用函数Connect()向服务器发送连接请求。
BOOL Connect(const SOCKADDR* lpSockAddr,int nSockAddrLen);
    lpSockAddr          连接的服务器地址结构
    nSockAddrLen     服务器地址结构长度

    具体调用:
 
   CSocket sock;
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(80);
    addr.sin_addr.S_un_S_addr = inet_addr("127.0.0.1");
    sock.Connect((SOCKADDR*)addr,sizeof(addr));//连接服务器


4.数据交换
    通过Send()和Receive()进行数据交换
函数原型
    virtual int Send(const void lpBuf,int nBuflen,int nFlags = 0);
    virtual int Receive(void* lpBuf,int nBuflen,int nFlags = 0);

    lpBuf: 数据缓冲区地址
    nBuflen:数据缓冲区的大小  
    nFlags : 数据发送或接收标志,一般情况都设置为0

    ...
    char buff[] = 'a';
    sock.Send(&buff,sizeof(buff),0);
    sock.Receive(&buff,sizeof(buff),0);

5.关闭套接字对象
     服务端和客户端的通信完成后,调用函数Close()将套接字对象关闭
    sock.Close();

     注意:CSocket类的头文件 afxsock.h  使用时,必须引入此文件 
    #include<afxsock.h> 




服务器端代码:
// SocketSever.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"WS2_32.lib")

int main(int argc, char* argv[])
{
	//1.用户初始化套接字库
	WSADATA data;				//定义WSADATA结构体对象
	WORD w = MAKEWORD(2,0);		//定义版本号
	char sztext[] = "欢迎你\r\n";	//定义并初始化发送到客户端的字符数组
	::WSAStartup(w,&data);		//初始化套接字库
	
	//2.创建套接字
	SOCKET s,s1;			//定义连接套接字和数据收发套接字句柄
	s = ::socket(AF_INET,SOCK_STREAM,0);	//创建TCP套接字
	sockaddr_in addr,addr2;		//定义套接字地址结构
	int n = sizeof(addr2);		//获取套接字地址结构大小
	addr.sin_family = AF_INET;	
	addr.sin_port = htons(75);
	addr.sin_addr.S_un.S_addr = INADDR_ANY;
	//3.绑定地址信息及启动监听
	::bind(s,(sockaddr*)&addr,sizeof(addr)); //绑定套接字
	::listen(s,5);
	printf("服务器已经启动 \r\n");
	//4.监听及接收请求
	while(true)
	{
		s1 = ::accept(s,(sockaddr*)&addr2,&n);//接收连接请求
		if(s1!=NULL)
		{
			printf("%s 已经连接上\r\n",inet_ntoa(addr2.sin_addr));
			::send(s1,sztext,sizeof(sztext),0);
		}
		//5.关闭套接字对象
		::closesocket(s);
		::closesocket(s1);
		//6.释放套接字库
		::WSACleanup();
		if(getchar())
		{
			return 0;
		}
		else
		{
			::Sleep(100);
		}
	}
}
客户端代码:
// SocketClient.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"WS2_32.lib")

int main(int argc, char* argv[])
{
	//1.用户初始化套接字库
	WSADATA data;				//定义WSADATA结构体对象
	WORD w = MAKEWORD(2,0);		//定义版本号
	::WSAStartup(w,&data);		//初始化套接字库
	
	//2.创建套接字
	SOCKET s;			//定义连接套接字
	char sztext[10] = {0};
	s = ::socket(AF_INET,SOCK_STREAM,0);	//创建TCP套接字
	sockaddr_in addr;		//定义套接字地址结构
	addr.sin_family = AF_INET;	
	addr.sin_port = htons(75);
	addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	printf("客户端已经启动 \r\n");
	//3.连接服务器
	::connect(s,(sockaddr*)&addr,sizeof(addr));
	//4.接收服务器消息
	::recv(s,sztext,sizeof(sztext),0);
	printf("%s \r\n",sztext);
	//5.关闭套接字对象
	::closesocket(s);
	//6.释放套接字库
	::WSACleanup();
	if(getchar())
	{
		return 0;
	}
	else
	{
		::Sleep(100);
	}
}








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值