接下来说一下如何用WinSock创建基于TCP/IP模型的客户端和服务器。

TCP可以提供两个计算机间可靠无误的数据传输,应用程序使用TCP通信时,会在两台计算机之间建立一个虚拟连接,连接之后计算机之间变可以以双向字节流进行数据交换。

下面说下简单的发送数据的客户端实现.

创建客户机的连接比较简单:

1.创建一个套接字,定义addrinfo对象并初始化这些值(该对象包含一个sockaddr结构)

struct addrinfo *result = NULL,*ptr = NULL,hints;ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;  //可以是IPv4或IPv6地址
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

调用getaddrinfo函数确定服务器ip地址(由命令行参数传递)和端口

#define DEFAULT_PORT "27015"// Resolve the server address and port
iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
if (iResult != 0) {printf("getaddrinfo failed: %d\n", iResult);WSACleanup();return 1;
}

socket原型:

socket(

IN int af,       //协议的地址族,使用IPv4来描述Winsock,设置为AF_INET

IN int type,     //套接字类型,TCP/IP设置为SOCK_STREAM,UDP/IP设置为SOCK_DGRAM

IN int protocol      //用于给定地址族和类型具有多重入口的传送限定,TCP设置为IPPROTO_TCP,UDP设置为IPPROTO_UDP

);

调用socket创建嵌套字,错误检测

SOCKET ConnectSocket = INVALID_SOCKET;
ptr=result;
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {printf("Error at socket(): %ld\n", WSAGetLastError());freeaddrinfo(result);WSACleanup();return 1;
}

2.连接到的服务器名。(在TCP/IP中就是监听服务器的IP地址和端口号)

iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {closesocket(ConnectSocket);ConnectSocket = INVALID_SOCKET;
}
//释放资源
freeaddrinfo(result);if (ConnectSocket == INVALID_SOCKET) {printf("Unable to connect to server!\n");WSACleanup();return 1;
}

客户端程序在创建套节字之后,要使用 connect函数请求与服务器连接,connect原型:

int WSAAPI connect(

IN SOCKET s,            //要建立连接的socket

IN const struct sockaddr FAR * name,    //指向保存要建立连接信息的地址结构

IN int namelen          //参数2指向地址结构的大小

);

3.发送和接收数据。

收发数据才是网络编程的主题,在已经建立连接的套接字上发生数据可以使用send或WSASend(WinSock2中),接受可用recv和WSARecv。收发数据都是用char类型(面向字节的数据)。

#define DEFAULT_BUFLEN 512int recvbuflen = DEFAULT_BUFLEN;char *sendbuf = "this is a test";
char recvbuf[DEFAULT_BUFLEN];int iResult;iResult = send(ConnectSocket, sendbuf, (int) strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR) {printf("send failed: %d\n", WSAGetLastError());closesocket(ConnectSocket);WSACleanup();return 1;
}printf("Bytes Sent: %ld\n", iResult);iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {printf("shutdown failed: %d\n", WSAGetLastError());closesocket(ConnectSocket);WSACleanup();return 1;
}do {iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);if (iResult > 0)printf("Bytes received: %d\n", iResult);else if (iResult == 0)printf("Connection closed\n");elseprintf("recv failed: %d\n", WSAGetLastError());
} while (iResult > 0);

所有收发数据返回的错误代码都是SOCKET_ERROR,一旦有错误返回,系统就会调用WSAGetLastError()获取详细错误信息。

常见错误:

WSAECONNABORTED和WSAECONNRESET:连接正在关闭(超时或者由于通信放正在关闭连接)
WSAEWOULDBLOCK:套接字处于非阻塞模式或异步状态。

使用send和recv函数原型。

int send(

SOCKET s, // 套节字句柄

const char FAR* buf,// 要发送的数据的缓冲区的地址

int len, // 缓冲区的长度

int flags  // 指定了的调用方式,通常设为0

);

int recv(

SOCKET s,

char FAR* buf,

int len,

int flags

);

send函数在一个连接的套节字上发送缓冲区内的数据,返回发送数据的实际字节数,recv函数从对方接收数据,并存储它到指定的缓冲区。flag参数在这两个函数中通常设为0。

在阻塞模式下,send将会阻塞线程的执行直到所有的数据发送完毕(或者一个错误的发生),而recv函数将返回尽可能多的当前信息,一直到缓冲区指定的大小。

函数执行失败返回INVALID_SOCKET(-1),应该调用closesocket函数将它关闭。如果没有错误发生,函数返回0,否则返回SOCKET_ERROR。函数用法如下:

int closesocket(

__in  SOCKET s // 函数唯一的参数就是要关闭的套节字的句柄

);

4.断开连接,关闭套接字(当客户机已经发出数据,可以使用shutdown函数和SD_SEND宏关闭发送套接字,客户机仍然允许接受来自服务器套接字上的数据)

iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {printf("shutdown failed: %d\n", WSAGetLastError());closesocket(ConnectSocket);WSACleanup();return 1;
}
closesocket(ConnectSocket);
WSACleanup();

附完整的客户端代码:

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <IPHlpApi.h>
#include <stdio.h>#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")
#pragma comment(lib, "Advapi32.lib")#define DEFAULT_PORT "27015"
#define DeFAULT_BUFLEN 512int main(int argc, char* argv[])
{WSADATA wsaData;int iResult;struct addrinfo *result = NULL, *ptr = NULL,hints;char *sendbuf = "this is a test";char recvbuf[DeFAULT_BUFLEN];int recvbuflen = DeFAULT_BUFLEN;SOCKET ConnectSocket = INVALID_SOCKET;if (argc != 2){printf("usage: %s server-name\n", argv[0]);}// 初始化winsockiResult = WSAStartup(MAKEWORD(2, 2), &wsaData);if (iResult != 0){printf("WSAStartup failed: %d\n", iResult);return 1;}ZeroMemory(&hints, sizeof(hints));hints.ai_family = AF_UNSPEC;hints.ai_socktype = SOCK_STREAM;hints.ai_protocol = IPPROTO_TCP;// 确定服务器地址和端口iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);if (iResult != 0){printf("getaddrinfo failed: %d\n", iResult);WSACleanup();return 1;}// 尝试连接到服务器地址,直到成功for (ptr = result; ptr != NULL; ptr = ptr->ai_next){// 创建套接字连接到服务器ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);if (ConnectSocket == INVALID_SOCKET){printf("Error at socket(): %ld\n", WSAGetLastError());freeaddrinfo(result);WSACleanup();return 1;}// 连接服务器iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);if (iResult == SOCKET_ERROR){closesocket(ConnectSocket);ConnectSocket = INVALID_SOCKET;continue;}break;}// 释放资源freeaddrinfo(result);if (ConnectSocket == INVALID_SOCKET){printf("Unable to connect to server!\n");WSACleanup();return 1;}// 发送sendbuf内容iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf) + 1, 0);if (iResult == SOCKET_ERROR){printf("send failed:%d\n", WSAGetLastError());closesocket(ConnectSocket);WSACleanup();return 1;}printf("Byte Send:%ld\n", iResult);// 数据发送完成之后断开连接iResult = shutdown(ConnectSocket, SD_SEND);if (iResult == SOCKET_ERROR){printf("shutdown faild: %d\n", WSAGetLastError());closesocket(ConnectSocket);WSACleanup();return 1;}// 收到回应之后关闭连接do {iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);if (iResult > 0)printf("Byte received: %d\n", iResult);else if (iResult == 0)printf("connection closed\n");elseprintf("recv failed: %d\n", WSACleanup());} while (iResult > 0);// 清除套接字closesocket(ConnectSocket);WSACleanup();return 0;
}

  本文链接: http://www.bugcoding.com/entry/10

转载于:https://www.cnblogs.com/NGNL/p/4534601.html

WinSock网络编程基础(2)客户端相关推荐

  1. WinSock网络编程基础(1)

    记录学习windows网络编程过程中遇到的问题和相关笔记 基本概念: Socket: socket起源于UNIX,Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.基于&qu ...

  2. 【Java——网络编程基础之客户端服务器连接】

    网络编程 1.1软件结构 1.2 网络通信协议 1.3 协议分类 1.4网络编程三要素 协议 IP地址 端口号 TCP通信程序 2.1 概述 2.2 Socket类 构造方法 成员方法 2.3 Ser ...

  3. WinSock网络编程基础(3)server

    上一篇讲的是简单的发送数据的客户端的实现.接下来讲的是如何实现收发数据服务器. 这里说的服务器其实就是一个进程,它需要等待任意数量的客户端与之建立起连接,以便响应它们的请求. 服务器必须在已知的名称上 ...

  4. Qt:Qt实现Winsock网络编程—TCP服务端和客户端通信(多线程)

    Qt实现Winsock网络编程-TCP服务端和客户端通信(多线程) 前言 感觉Winsock网络编程的api其实和Linux下网络编程的api非常像,其实和其他编程语言的网络编程都差不太多.博主用Qt ...

  5. Qt:Qt实现Winsock网络编程—非阻塞模式下的简单远程控制的开发(WSAAsyncSelect)

    Qt实现Winsock网络编程-非阻塞模式下的简单远程控制的开发(WSAAsyncSelect) 前言 这边博客应该是 Qt实现Winsock网络编程-TCP服务端和客户端通信(多线程) 的姐妹篇,上 ...

  6. 看完之后保证你对socket编程步骤胸有成竹。 C++ Socket网络编程基础详解(TCP)

    C++ Socket网络编程基础详解(TCP版) ​    网络编程,就是编写程序使得两台计算机交换数据,其实从本质上来讲,网络编程最终所实现的功能,和我们文件的输入输出很相似,只是文件输入输出的对象 ...

  7. 《爬虫与网络编程基础》学习

    <爬虫与网络编程基础>学习 任务1:计算机网络基础 Step1-2 Step 3:关于XML格式的学习 XML文件格式 XML文件的常见操作 1.构建xml格式文件 2. 保存XML文件 ...

  8. 网络编程基础之C/S架构和TCP/IP协议

    一.何谓C/S架构 C指的是client(客户端软件),S指的是Server(服务端软件),既然我们的的标题是网络编程基础, 那我们就一起来学习怎样写一个C/S架构的软件,实现服务端与客户端软件基于网 ...

  9. python网络编程证书_《Python网络编程基础》笔记

    python网络编程基础 ================== Author: lujun9972 Date: 2013-03-08 22:29:20 CST Table of Contents == ...

最新文章

  1. oracle索引本地打钩,Oracle
  2. CV:Win10下深度学习框架安装之Tensorflow/tensorflow_gpu+Cuda+Cudnn(最清楚/最快捷)之详细攻略(图文教程)
  3. linux杀sqlplus进程,sqlplus / as sysdba 在linux系统所发起进程
  4. 推荐 GitHub 2K+ 星:前端监控工具 - webfunny 项目
  5. 多线程三种同步方式(模拟银行取款)
  6. 电气技术应用和计算机应用,电气技术应用专业介绍-1.ppt
  7. 软件研发成本估算过程之估算软件规模概述
  8. 检查浏览器支持(Checking browser support),这个是很广泛的一个知识!
  9. es java字段匹配多个值_es multiMatchQuery多字段匹配异常
  10. android控件在同一水平,android – 在linearlayout中水平对齐按钮,间距相等
  11. 蓝桥杯 算法训练 最大最小公倍数
  12. ROS学习笔记(一)——软件版本的选择
  13. 云计算的核心技术,主要有哪些?
  14. MATLAB数字图像处理详细总结
  15. TOGAF9中文版(五)
  16. 应用一个基于Python的开源人脸识别库,face_recognition
  17. echarts2获取series下的data数值
  18. 2022新版iApp工具箱源码+有聊天系统等等
  19. AdBlock Plus 大幅飙升 Firefox 内存开销
  20. 华硕ezflash3找不到u盘_通过华硕BIOS Tools - EZ Flash 2 更新主板BIOS

热门文章

  1. 图解网络:组建一个网络需要用到哪些硬件设备?
  2. cmd控制台窗体大小设置
  3. 关于《小萝莉的猴神大叔》些许体会
  4. 使用jquery validate结合zui作表单验证
  5. 清华大学计算机系2016名单,关于电子系2016 级、2017 级本科生分流至微纳电子系学生名单公示...
  6. 攻防世界 pwn进阶区----No.012 babyfengshui 解题思路
  7. 操作系统Unix、Windows、Mac OS、Linux的故事
  8. ASCII码_字符与数字转换等问题
  9. fiddler相关1(安装、设置)
  10. web-log-parser 安装记录