Socket编程(1)

1、Socket编程的主要步骤与重要函数

Socket编程在windows上首先需要<WinSock2.h>这个头文件和“ws2_32.lib”这个lib库文件。

Soket编程一般分为UDP通信与TCP通信,那么简单的UDP通信与TCP通信前面的过程基本都是一样的,只有在收发数据的时候会有不同。

UDP通信的一般步骤:

(1)、初始化

	WSADATA wd;
	WSAStartup(0x0202,&wd);  //初始化加载ws2_32.lib
WSAStartup是Socket编程的初始化工作

(2)、建立套接字

	SOCKET sock = socket(AF_INET,SOCK_DGRAM,0);
	if(sock == INVALID_SOCKET)
	{
		cout<<"socket创建失败! 错误码:"<<WSAGetLastError()<<endl;
	}
	SOCKET socket(int af, int type,int protocol);

socke函数是建立套接字,返回一个描述符指向成功的socket。

af : 一般指定为 AF_INET,表示使用UDP,TCP网络

type:  一般分为两类,SOCK_STREAM 表示TCP通信,SOCK_DGRAM表示UDP通信

protocol: 一般设定为0。

(3)、绑定端口

	int bind(SOCKET s,const sockaddr* name,int namelen)

bind函数将套接字绑定在指定的端口上,绑定成功返回0,绑定失败返回-1

s: 套接字

name: sockaddr结构体,sockaddr_in与sockaddr可以互相转化,一般常用sockaddr_in,最后再强制转化为sockaddr

sockaddr_in结构体如下

	struct sockaddr_in{
	   short sin_family;
	   unsigned short sin_port;
	   struct in_addr sin_addr;
	   char sin_zero[8];
	};
sin_family: 指定为AF_INET,表示UDP,TCP家族

sin_port: 指定端口

sin_addr: 指定IP

sin_zreo: 保证sockaddr_in与sockaddr有相同的大小,便于相互转化

实例:

	const int PORT = 8080;
	sockaddr_in sa = {AF_INET,htons(PORT)};
	int n = bind(sock,(sockaddr*)&sa,sizeof(sa));
	if(SOCKET_ERROR == n)
	{
		cout<<"bind绑定端口失败! 错误码:"<<WSAGetLastError()<<endl;
	}
套接字绑定了8080端口,其中端口需要用htons反转下,因为网络上的字节序与计算机上的相反,如果是服务器端绑定端口可以不设置IP,这样服务器可以接受本机上所有网段的消息。

(4)、监听

监听只有是TCP服务器端才会有的。

	int listen(
	  SOCKET s,
	  int    backlog
	)
s: 套接字

backlog: The maximum length of the queue of pending connections. 

5)、等待连接

只有TCP服务器端才会有,服务器端等待客户端的socket连接

	SOCKET
	accept(
		SOCKET s,
		struct sockaddr* addr,
		int* addrlen
		);
接受成功,则返回一个指向客户段的套接字。

s: 服务器端的套接字

addr: 用于保存客户端的信息(包括:IP,端口等)

addrlen: addr结构体的大小

(6)、连接

只有客户端才会有,向服务器端发送连接请求

	int
	connect(
		SOCKET s,
		const struct sockaddr* name,
		int namelen
		
s: 客户端的套接字

name: 服务器端地址信息(需要制定IP,端口)

namelen: 结构体name的大小

连接成功,则返回非0,否则返回0

(7)、发送数据

发送数据分为UDP发送与TCP发送,UDP发送使用sendto函数,TCP发送使用send函数

	int
	sendto(
		SOCKET s,
		const char FAR * buf,
		int len,
		int flags,
		const struct sockaddr FAR * to,
		int tolen
		);
s: 发送端的套接字

buf: 发送数据的缓存

len: 发送数据的大小

flags: 设为0

to: 接收端的地址信息(需要指定IP,端口)

tolen: 接受端结构体的大小

函数返回实际发送数据的大小

	int
	send(
		SOCKET s,
		const char FAR * buf,
		int len,
		int flags
		);
参数: 与senfto类同

(8)、接受数据

接受数据有两个函数,recv 与 recvfrom

	int
	recv(
		SOCKET s,
		char FAR * buf,
		int len,
		int flags
		);
s: 接收端(服务器端)的套接字

buf: 接受缓存

len: 缓存大小

flags: 一般设为0

函数返回实际接受的大小,-1表示接受失败

	int
	recvfrom(
		SOCKET s,
		char FAR * buf,
		int len,
		int flags,
		struct sockaddr FAR * from,
		int FAR * fromlen
		);
from: 发送端的地址信息

fromlen: from结构体的大小

recvfrom 与 recv 最大的区别就是,recvfrom可以获取发送端的地址信息(包括:IP与端口)

(9)、getpeername 与 getsockname

getpeername可以获取对方IP,端口信息(只限TCP)

getsockname可以获取本机IP,端口信息

	int
	getpeername(
		SOCKET s,
		struct sockaddr FAR * name,
		int FAR * namelen
		)
s: 发送方的套接字

name: 保存发送方的地址信息

namelen: name结构体的大小

	int
	getsockname(
		SOCKET s,
		struct sockaddr FAR * name,
		int FAR * namelen
		);
s: 本机的套接字

其余:类同

2、示例

UDP通信--发送端

	// test_UDP_send.cpp : Defines the entry point for the console application.
	//

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

	using namespace std;

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

	int _tmain(int argc, _TCHAR* argv[])
	{
		WSADATA wd;
		WSAStartup(0x0202,&wd);
		SOCKET sock = socket(AF_INET,SOCK_DGRAM,0);
		if(sock == INVALID_SOCKET)
		{
			cout<<"sock 创建失败!"<<endl;
			return -1;
		}
		sockaddr_in sa = {AF_INET,htons(7070)};
		int n = bind(sock,(sockaddr*)&sa,sizeof(sa));
		if(n == SOCKET_ERROR)
		{
			cout<<"bind 失败!"<<endl;
			return -1;
		}
		sockaddr_in accept = {AF_INET,htons(8080)};				//指定接受端的端口与IP
		accept.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
		char s[128];
		while(1)
		{
			cout<<"请输入发送的数据: ";
			gets(s);
			sendto(sock,s,strlen(s),0,(sockaddr*)&accept,sizeof(accept));
		}
		return 0;
	}

UDP通信--接收端

	// test_UDP_recv.cpp : Defines the entry point for the console application.
	//

	#include "stdafx.h"


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

	using namespace std;

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

	int _tmain(int argc, _TCHAR* argv[])
	{
		WSADATA wd;
		WSAStartup(0x0202,&wd);
		SOCKET sock = socket(AF_INET,SOCK_DGRAM,0);
		if(sock == INVALID_SOCKET)
		{
			cout<<"sock 创建失败!"<<endl;
			return -1;
		}
		sockaddr_in sa = {AF_INET,htons(8080)};
		int n = bind(sock,(sockaddr*)&sa,sizeof(sa)); //绑定了8080端口
		if(n == SOCKET_ERROR)
		{
			cout<<"bind 失败!"<<endl;
			return -1;
		}
		char s[128]; //接受数据的缓存
		n = 0;
		while((n = recv(sock,s,sizeof(s)-1,0))>0)
		{
			s[n] = 0;
			cout<<s<<endl;
		}
		return 0;
	}

TCP通信--服务器端

	// test_TCP_server.cpp : Defines the entry point for the console application.
	//

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

	using namespace std;

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

	int _tmain(int argc, _TCHAR* argv[])
	{
		WSADATA wd;
		WSAStartup(0x0202,&wd);
		SOCKET sock = socket(AF_INET,SOCK_STREAM,0);
		if(sock == INVALID_SOCKET)
		{
			cout<<"sock 失败!"<<endl;
			return -1;
		}
		sockaddr_in sa = {AF_INET,htons(8080)}; 
		int n = bind(sock,(sockaddr*)&sa,sizeof(sa));
		if(n == SOCKET_ERROR)
		{
			cout<<"bind 失败!"<<endl;
			return -1;
		}
		listen(sock,5);//监听
		SOCKET acceptSock;
		sockaddr_in client = {0};
		int nLen = sizeof(client);
		if((acceptSock = accept(sock,(sockaddr*)&client,&nLen)) == INVALID_SOCKET)//等待连接,会阻塞在这里
		{
			cout<<"accept 失败!"<<endl;
			return -1;
		}
		cout<<"有客户端连接:"<<inet_ntoa(client.sin_addr)<<"-"<<htons(client.sin_port)<<endl;
		char s[128];
		while((n = recv(acceptSock,s,sizeof(s)-1,0)) > 0 )
		{
			s[n] = 0;
			cout<<s<<endl;
		}
		return 0;
	}


TCP通信--客户端

	// test_TCP_client.cpp : Defines the entry point for the console application.
	//

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

	using namespace std;

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

	int _tmain(int argc, _TCHAR* argv[])
	{
		WSADATA wd;
		WSAStartup(0x0202,&wd);
		SOCKET sock = socket(AF_INET,SOCK_STREAM,0);
		if(sock == INVALID_SOCKET)
		{
			cout<<"sock 失败!"<<endl;
			return -1;
		}
		sockaddr_in sa = {AF_INET}; //客户端不指定端口,系统会分配一个随机端口
		int n = bind(sock,(sockaddr*)&sa,sizeof(sa));
		if(n == SOCKET_ERROR)
		{
			cout<<"bind 失败!"<<endl;
			return -1;
		}
		sockaddr_in server = {AF_INET,htons(8080)};				//指定服务器端的端口与IP
		server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
		n = connect(sock,(sockaddr*)&server,sizeof(server));
		if(n == SOCKET_ERROR)
		{
			cout<<"连接服务器失败!"<<endl;
			return -1;
		}
		else	
			cout<<"连接服务器成功!"<<endl;
		char s[128];
		while(1)
		{
			cout<<"请输入发送的数据:";
			gets(s);
			send(sock,s,strlen(s),0);
		}
		return 0;
	}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值