Socket编程(1)

来源:互联网 发布:c语言函数写法 编辑:程序博客网 时间:2024/05/11 20:31

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连接

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

s: 服务器端的套接字

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

addrlen: addr结构体的大小

(6)、连接

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

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

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

namelen: 结构体name的大小

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

(7)、发送数据

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

intsendto(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: 接受端结构体的大小

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

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

(8)、接受数据

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

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

buf: 接受缓存

len: 缓存大小

flags: 一般设为0

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

intrecvfrom(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,端口信息

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

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

namelen: name结构体的大小

intgetsockname(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)};//指定接受端的端口与IPaccept.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)};//指定服务器端的端口与IPserver.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;}elsecout<<"连接服务器成功!"<<endl;char s[128];while(1){cout<<"请输入发送的数据:";gets(s);send(sock,s,strlen(s),0);}return 0;}


0 0
原创粉丝点击