windows:简单的socket通信

目录

说明

效果展示

服务端代码

客户端代码

函数和结构体详情


说明

这个示例是写了一个服务端和一个客户端,客户端发数据,服务器接数据。

服务端地址:10.131.8.185              客户端地址:10.131.8.164

 

注意事项:

1、需要先运行服务端,再运行客户端

2、服务器和客户端都在同一台机器运行的时候,ip地址双方可以都设置为127.0.0.1

3、服务器和客户端不在同一台机器运行的时候,服务器绑定套接字的时候,ip需要设置为自己的ip,客户端连接套接字的ip需要设置为连接方的ip(也就是服务器ip)

4、如果在vs中Ctrl+F5运行控制台不显示数据,可以考虑直接运行编译生成的exe文件

 

效果展示

客户端和服务端不同机器上

 

 

服务端代码

#include <iostream>
#include <winsock.h>
using namespace std;

#pragma comment(lib, "ws2_32.lib")

#define DEF_PORT	6666

//服务端
int main(int argc, char *argv[])
{
	//初始化DLL
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		cout << "初始化DLL失败" << endl;
		goto end;
	}
	cout << "初始化DLL成功" << endl;

	//创建套接字
	SOCKET serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	
	//绑定套接字
	SOCKADDR_IN serverAddr;
	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;							//使用ipv4地址
	serverAddr.sin_addr.S_un.S_addr = inet_addr("10.131.8.185");//本机地址,如果客户端和服务器在同一机器,可以使用127.0.0.1
	serverAddr.sin_port = htons(DEF_PORT);						//端口号
	if (bind(serverSock, (SOCKADDR*)&serverAddr, sizeof(SOCKADDR)) == SOCKET_ERROR)
	{
		cout << "套接字绑定失败" << endl;
		goto end;
	}
	cout << "套接字绑定成功" << endl;

	//进入监听状态
	if (listen(serverSock, SOMAXCONN) < 0)//参数2:挂机连接队列的最大长度,SOMAXCONN:让系统自动选择合适的个数
	{
		cout << "套接字监听失败" << endl;
		goto end;
	}
	cout << "套接字监听成功" << endl;

	//接收客户端请求
	SOCKADDR_IN clientAddr;
	int len = sizeof(sockaddr_in);
	SOCKET clientSock = accept(serverSock, (SOCKADDR*)&clientAddr, &len);//阻塞等待客户端连接
	if (clientSock == SOCKET_ERROR)
	{
		cout << "与客户端连接失败" << endl;
		goto end;
	}
	cout << "与客户端连接成功..." << endl;

	//接收数据
	int recvLen = 0;
	char recvBuf[1024];
	memset(recvBuf, 0, 1024);
	while (1)
	{
		recvLen = recv(clientSock, recvBuf, 1024, NULL);//接收消息
		cout << "from client " << inet_ntoa(clientAddr.sin_addr) << ": " << recvBuf << endl;
		memset(recvBuf, 0, 1024);
	}

end:
	closesocket(serverSock);
	closesocket(clientSock);
	WSACleanup();//释放DLL资源
	return 0;
}

 

 

客户端代码

#include <iostream>
#include <winsock.h>
using namespace std;

#pragma comment(lib, "ws2_32.lib")

#define DEF_PORT	6666

//客户端
int main(int argc, char* argv[])
{
	//初始化DLL
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		cout << "初始化DLL失败" << endl;
		goto end;
	}
	cout << "初始化DLL成功" << endl;

	//创建套接字
	SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	//向服务器发送请求
	SOCKADDR_IN sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));
	sockAddr.sin_family = AF_INET;                            //使用ipv4地址
	sockAddr.sin_addr.S_un.S_addr = inet_addr("10.131.8.185");//服务器ip,如果客户端和服务端在同一机器运行可以使用127.0.0.1
	sockAddr.sin_port = htons(DEF_PORT);                      //端口号
	if (connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)) == SOCKET_ERROR)//连接服务器
	{
		cout << "连接服务端失败, 错误码:" << WSAGetLastError() <<  endl;
		goto end;
	}
	cout << "连接服务端成功..." << endl;


	//向服务器发送数据
	char sendBuf[1024];
	memset(sendBuf, 0, 1024);
	while (1)
	{
		cin >> sendBuf;
		send(sock, sendBuf, strlen(sendBuf), NULL);//发送消息
		memset(sendBuf, 0, 1024);
	}

end:
	closesocket(sock);
	WSACleanup();//释放DLL资源
	while (1);
	return 0;
}

 

函数和结构体详情

SOCKADDR_IN

typedef struct sockaddr_in SOCKADDR_IN;

/*
 * @sin_family: ip地址类型,  使用:AF_INET 和 AF_INET6,前者代表ipv4,后者ipv6
 * @sin_port:   端口号,      使用:1024~65535
 * @sin_addr:   ip地址,       使用:sin_addr.Sun.S_addr = inet_addr("127.0.0.1")
 * @sin_zero:   为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
 */
struct sockaddr_in {
        short   sin_family;            
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};
/*
 * @S_addr: IP地址,通常使用:inet_addr("127.0.0.1")
 */
typedef struct in_addr {
        union {
                struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
                struct { USHORT s_w1,s_w2; } S_un_w;
                ULONG S_addr;
        } S_un;

 

SOCKADDR

typedef struct sockaddr SOCKADDR;

/*
 * Structure used by kernel to store most
 * addresses.
 */
struct sockaddr {
        u_short sa_family;              /* address family */
        char    sa_data[14];            /* up to 14 bytes of direct address */
};

 

socket

/*
 * @af:         ip地址类型,      使用:AF_INET 和 AF_INET6,前者代表ipv4,后者ipv6
 * @type:       数据传输方式,    使用:SOCK_STREAM 和 SOCK_DGRAM,前者流形式,后者报文
 * @protocol:   传输协议,         使用:IPPROTO_TCP 和 IPPTOTO_UDP
 */
SOCKET PASCAL FAR socket (
                          _In_ int af,
                          _In_ int type,
                          _In_ int protocol);

 

bind

/*
 * @s:          ip地址类型,      使用:AF_INET 和 AF_INET6,前者代表ipv4,后者ipv6
 * @addr:       sockaddr结构体变量    
 * @namelen:    sockaddr结构体长度      
 * @返回值:     返回SOCKET_ERROR,表示绑定失败 
 */
int PASCAL FAR bind (
                     _In_ SOCKET s,
                     _In_reads_bytes_(namelen) const struct sockaddr FAR *addr,
                     _In_ int namelen);

 

listen

/*
 * @s:          需要监听的套接字
 * @backlog:    挂机连接队列的最大长度,  通常使用SOMAXCONN,让系统自动选择合适的个数 
 * @返回值:     如果小于0,表示监听失败        
 */
int PASCAL FAR listen (
                       _In_ SOCKET s,
                       _In_ int backlog);

 

accept

/*
 * @s:       服务器套接字
 * @addr:    存储连接的客户端地址信息    
 * @addrlen:地址信息结构体长度     
 * @返回值:  连接的客户端套接字   
 */
SOCKET PASCAL FAR accept (
                          _In_ SOCKET s,
                          _Out_writes_bytes_opt_(*addrlen) struct sockaddr FAR *addr,
                          _Inout_opt_ int FAR *addrlen);

 

connect

/*
 * @s:       服务器套接字
 * @addr:    存储连接的客户端地址信息    
 * @addrlen:地址信息结构体长度    
 * @返回值:  返回SOCKET_ERROR表示失败    
 */
int PASCAL FAR connect (
                        _In_ SOCKET s,
                        _In_reads_bytes_(namelen) const struct sockaddr FAR *name,
                        _In_ int namelen);

 

send

/*
 * @s:        要发送的主机套接字(给谁发,就填谁)
 * @buf:      发送的数据  
 * @len:     发送数据的长度   
 * @flags:   指定调用方式的标志集,一般设置为NULL, 参数有两个: MSG_DONTROUTE,MSG_OOB  
 */
int PASCAL FAR send (
                     _In_ SOCKET s,
                     _In_reads_bytes_(len) const char FAR * buf,
                     _In_ int len,
                     _In_ int flags);

 

recv

/*
 * @s:        要接收的主机套接字(谁给我发,就填谁)
 * @buf:      接收的数据  
 * @len:     接收数据的长度   
 * @flags:   指定调用方式的标志集,一般设置为NULL, 参数有两个: MSG_DONTROUTE,MSG_OOB  
 */
int PASCAL FAR recv (
                     _In_ SOCKET s,
                     _Out_writes_bytes_to_(len, return) __out_data_source(NETWORK) char FAR * buf,
                     _In_ int len,
                     _In_ int flags);

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值