Socket编程(TCP)

服务端的建立:

1, 加载SOCKET版本

2, 创建socket

3, 创建SOCKADDR_IN结构变量, 设置IP, 端口, 与地址族

4, 绑定IP与端口

5, 打开监听

6, 接收客户端连接请求

7, 开启通信.


客户端的建立:

1, 加载SOCKET版本

2, 创建socket

3, 创建SOCKADDR_IN结构变量, 设置IP, 端口, 与地址族

4, 连接服务端

5, 开启通信


windows下服务端的例子:

#include "stdafx.h"
#include <WinSock2.h>


int _tmain(int argc, _TCHAR* argv[])
{
	using std::cout;
	
	WORD wVersion;
	WSADATA wsaData;

	wVersion = MAKEWORD(2, 2); //设置版本
	//WSAStartup 加载SOCKET版本, 成功返回0, 否则返回-1
	if (WSAStartup(wVersion/*设定的版本号*/, 
		&wsaData/*OUT参数, 获取加载的版本信息*/))
	{
		cout<<"加载SOCK出错";
		std::cin.get();
		return -1;
	}

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) !=2)
	{//验证版本信息是不为2, 2
		cout<<"加载SOCK版本出错";
		std::cin.get();
		//WSACleanup释放资源, 终止对SOCKET动态库的使用
		WSACleanup();
		return -1;
	}

	int sockLength = sizeof(SOCKADDR);

	//socket创建SOCKET, 成功返回一个新的SOCKET数据类型的套接字描述符, 失败返回 INVALID_SOCKET
	SOCKET sockServer = socket(AF_INET/*地址族*/, 
		SOCK_STREAM/*指定流式套接字*/, 
		0/*一般设置为0, 自动选择一个合适的协议*/);

	SOCKADDR_IN sAddress;
	//inet_addr(将字符串IP型式转换为指定的ulong类型地址描述)
	//inet_ntoa(将指定的ulong类型地址描述转换成字符串IP型式)
	sAddress.sin_addr.S_un.S_addr = inet_addr("192.168.1.100");
	sAddress.sin_family = AF_INET;
	//htons把一个u_short类型的值从主机字节顺序转换为TCP/IP网络字节顺序
	//htonl把一个u_long类型的值从主机字节顺序转换为TCP/IP网络字节顺序
	sAddress.sin_port = htons(7777);
	//bind, 将该套接字绑定到指地的IP和端口上, 成功返回0, 否则返回 SOCKET_ERROR
	bind(sockServer, //创建的SOCKET
		(SOCKADDR*)&sAddress, //地址信息
		sockLength/*SOCKADDR的字节长度sizeof(SOCKADDR)*/);
	//listen, 开启监听, 成功返回0, 否则返回SOCKET_ERROR
	listen(sockServer,//创建的SOCKET
		10/*打开服务会监听的客户数量*/);

	SOCKADDR_IN clientAddress;
	while(TRUE)
	{
		//accept接收客户端发送的连接请求, 成功, 返回该客户端的SOCKET, 否则返回-1
		SOCKET client = accept(sockServer, //服务端SOCKET
			(SOCKADDR*)&clientAddress, //用来接收客户端地址
			&sockLength/*sizeof(SOCKADDR)*/);
		cout<<"链接OK";
		char sendBuffer[512];
		sprintf(sendBuffer, "%s 以登录成功", 
			inet_ntoa(clientAddress.sin_addr)/*将ulong型式地址转换成字符串型式的IP地址*/);
		//send发送消息
		send(client, sendBuffer, strlen(sendBuffer) + 1/*这里注要多加1用来存放\0*/, 0);
		char recvBuffer[512] = {0};
		//recv接收消息, 失败返回0或者-1
		recv(client, recvBuffer, 512, 0);
		cout<<recvBuffer;
		closesocket(client);
	}
	cout<<"成功";
	std::cin.get();
	WSACleanup();
	return 0;
}

windows下客户端的例子:

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
	WORD wVersion;
	WSADATA wsaData;
	wVersion = MAKEWORD(2, 2); 

	if (WSAStartup(wVersion, &wsaData))
	{
		std::cout<<"加载SOCK出错";
		std::cin.get();
		return -1;
	}

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		std::cout<<"加载SOCK版本出错";
		std::cin.get();
		WSACleanup();
		return -1;
	}
	SOCKET client = socket(AF_INET, SOCK_STREAM, 0);

	SOCKADDR_IN hostAddress;
	hostAddress.sin_addr.S_un.S_addr = inet_addr("192.168.1.100");
	hostAddress.sin_family = AF_INET;
	hostAddress.sin_port = htons(7777);
	//connect连接指定的地址与端口
	int i = connect(client, (SOCKADDR*)&hostAddress, sizeof(SOCKADDR));
	if (i == 0)
	{
		std::cout<<"连接成功\n";
	}
	char recvBuffer[512];
	recv(client, recvBuffer, 512, 0);
	std::cout<<recvBuffer;
	char sendBuffer[511];
	sprintf(sendBuffer, "客户端 登录成功");
	send(client, sendBuffer, strlen(sendBuffer) + 1/*这个很关键*/, 0);

	closesocket(client);
	WSACleanup();

	std::cin.get();
	return 0;
}


这里仅是未了说明套接字的使用, 在实际应用当中, 都必需结合多线程处理套接字, 最好还要封装之后再使用


windows下获取本机IP:

char * IegadSock::GetHostIp()
{//获取本机IP
	WSADATA wData;
	unsigned int version = MAKEWORD(2, 2);
	if (WSAStartup(version, &wData))
	{
		return 0;
	}
	if (LOBYTE(wData.wVersion) != 2 || HIBYTE(wData.wVersion) != 2)
	{
		return 0;
	}
	char host_name[255]; //计算机名
	if (gethostname(host_name/*输出参数*/, sizeof(host_name)) == -1) //该函数获取计算机名
	{//该函数, 成功返回0
		return 0;
	}
	//gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针,失败返回NULL
	HOSTENT * phe = gethostbyname(host_name/*计算机名*/);
	if (!phe)
	{
		return 0;
	}
	in_addr addr;
	//获取HOSTENT中的地址列表中第一个地址,并转换成字符串
	memcpy(&addr, phe->h_addr_list[0], sizeof(in_addr));
	char * IpString = inet_ntoa(addr);
	WSACleanup();
	return IpString;
}


这里是Linux下的服务端:

#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <iostream>

int main()
{
   //unlink("server_socket");
   int host = socket(AF_INET, SOCK_STREAM, 0);
   if(host == -1)
   {
     std::cout<<"init error\n";
     return -1;
   }
   std::cout<<"init done\n";
   sockaddr_in s_add;
   s_add.sin_family = AF_INET;
   s_add.sin_addr.s_addr= inet_addr("192.168.1.104");
   s_add.sin_port=htons(7777);
   int err = bind(host, (sockaddr*)&s_add, sizeof(sockaddr));
   if (err == -1)
   {
     std::cout<<"bind error\n";
   }
   std::cout<<"bind done\n";
   err = listen(host, 10);
   if (err == -1)
   {
     std::cout<<"listen error\n";
   }
   std::cout<<"listen...\n";


   sockaddr_in c_add;
   int len = sizeof(c_add);
   int clnt = accept(host, (sockaddr*)&c_add, (socklen_t*)&len/*这里和windows下有区别*/);
   if(clnt == -1)
   {
      std::cout<<"accpet error\n";
   }
   std::string sendMsg = "Hello guy\n";
   err = write(clnt, sendMsg.c_str(), sendMsg.size() + 1);
   if(err == -1)
   {
     std::cout<<"write error\n";
   }
   char msg[1024] = {0};
   read(clnt, msg, 1024);
   std::cout<<msg<<std::endl;
   close(clnt);
   close(host);
   return 0;
}


在linux下,是不需要加载版本的.也就是(WSAStartup()的调用)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值