Socket编程在windows上首先需要<WinSock2.h>这个头文件和“ws2_32.lib”这个lib库文件。
Soket编程一般分为UDP通信与TCP通信,那么简单的UDP通信与TCP通信前面的过程基本都是一样的,只有在收发数据的时候会有不同。
UDP通信的一般步骤:
(1)、初始化
WSADATA wd; WSAStartup(0x0202,&wd); //初始化加载ws2_32.libWSAStartup是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 namelens: 客户端的套接字
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: 本机的套接字
其余:类同
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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/dream_whui/article/details/48086681