建立客户端的 Socket:

客户端应用程序首先也是调用 WSAStartup() 函数来初始化 Winsock 的动态连接库,然后同样

调用 socket() 来建立一个 TCP 或 UDP Socket(相同协议的Socket 才能相遇,TCP 对 TCP,UDP 对 UDP)。

与服务器的 Socket 不同的是,客户端的 Socket 可以调用 bind() 函数,来指定 IP 地址及端口号 port。

但也可以不调用 bind() 函数。而由 Winsock 来自动设定 IP 地址及端口号 port。

发起连接申请:

当客户端程序需要连接服务器时,客户端程序的 Socket 调用 connect() 函数监听,与 name 所指定的计算机的特定

端口上的服务器端 Socket 进行连接。函数调用成功返回 0,否则返回 SOCKET_ERROR。

connect() 函数原型

int connect(

    SOCKET s,          // 客户端流套接字

    const struct sockaddr FAR *name,  // 要连接的套接字的地址结构。

    int namelen        // 指明套接字的地址结构的长度。

);

函数示例:

//...

     struct sockaddr_in name;

     name.sin_family = FA_INET;

     name.sin_port = htons();

     name.sin_addr.s_addr = inet_addr("127.0.0.1");

     connect(sSocket,(struct sockaddr *)&name,sizeof(name));

//...

inet_addr() 可以用来转化字符串,主要用来将一个十进制的数转化为二进制数,多用于 IPv4 的 ip 转化。

返回:若字符串有效则将字符串转换为32位二进制网络字节序的IPV4地址,否则为INADDR_NONE。

用 Socket 实现数据的传送:

服务器和客户端分别创建 Socket 并连接后,就开始数据的传递。网络编程数据传送涉及两大协议:TCP/IP 和 UDP 协议。

Stream (TCP) Socket:提供双向,可靠,有次序,不重复的资料传送。

Datagram (UDP) Socket:虽然提供双向的通信,但是没有 可靠,有次序,不重复的保证,

所以 UDP 传送数据可能收到无次序,重复的资料,甚至资料在传输过程中会泄露。

一般情况下 TCP Socket 的数据发送和接收是调用 send() 和 recv() 这两个函数来完成的,

而 UDP Socket 则是调用 sendto() 和 recvfrom() 这两个函数,这两个函数调用成功返回发送或接收的资料长度,

否则返回 SOCKET_ERROR。

send() 函数原型:

int send(

    SOCKET s,          // 指定发送端套接字描述符。

    const char FAR *buf,  // 指明一个存在应用程序要发送数据的缓冲区。

    int len,      // 指明实际要发送的数据的字节数。

    int flags    // 一般置 0。

);

不论是客户端还是服务端的应用程序都用 send() 函数向 TCP 连接的另一端发送数据。

客户端一般用 send() 函数 向服务器发送请求,而服务器通常用 send() 函数来向客户端程序发送应答。

对于同步 Socket 的 send() 函数执行流程,当调用它时,send 先比较待发送数据的长度(len)和套接字s 的发送端缓冲区大小。

如果 len 大于 s 的发送缓冲区的长度,该函数就返回 SOCKET_ERROR,发送失败。

反之,那么 send 先检查协议是否正在发送 s 发送缓冲区的数据。如果是,就等待协议把数据发送完,

如果协议还没有开始发送 s 的发送缓冲区的数据 或者 s 的发送缓冲区中没有数据,

那么send 就比较 s  的发送缓冲区的剩余空间和 len 的大小。如果 len 大于剩余空间大小,

send 就一直等待协议把 s 的发送缓冲区中的数据发送完,反之,send 就仅仅把 buf 中的数据复制到剩余空间里

注意并不是 send 把 s 的发送缓冲区中的数据传到连接的另一端的,而是协议传的,

send 仅仅是把 buf 中的数据复制到 s 的发送缓冲区的剩余空间里)。

如果 send() 函数复制数据成功,就返回实际复制的字节数,否则,就返回 SOCKET_ERROR。

如果 send() 函数在等待协议传送数据时网络断开,也返回 SOCKET_ERROR。

send() 函数把 buf 中的数据成功复制到 s 的发送缓冲区的剩余空间中后它就返回了,但是此时这些数据

并不一定马上就传到连接的另一端。

如果协议在后续的传递过程中出现网络错误的话,那么下一个 socket 函数就会返回 SOCKET_ERROER。

提示:

每一个除 send 外的 socket 函数在执行最开始总要等待套接字的发送缓冲区中的数据被协议传送完毕才能继续,

如果出现网络错误,那么该 socket 函数就返回 SOCKET_ERROR。

recv() 函数原型:

int recv(

    SOCKET s,      // 指定接收端套接字描述符。

    char FAR *buf,  // 指明一个缓冲区,该缓冲区用来存放 recv() 函数接收到的数据。

    int len,     // 指明 buf 的长度。

    int flags   // 一般置 0。

);

不论客户端还是服务器端应用程序都用 recv() 函数从 TCP/IP 连接的另一端接收数据。

对于同步 Socket 的 recv() 函数执行流程,当调用它时,recv() 函数先等待 s 的发送缓冲区中的数据传输完毕。

如果协议在传送 s 的发送缓冲区中的数据时出现网络错误的话,那么 recv() 函数就会返回 SOCKET_ERROER。

如果 s 的发送缓冲区中没有数据 或者数据被协议接收完毕后,recv() 函数 会先检查套接字 s 的接收缓冲区,

如果 s 的接收缓冲区中没有数据或协议正在接收数据,那么 recv() 函数就会一直等待,直到数据接收完毕。

当协议把数据接收完毕,recv() 函数就把 s 的接收缓冲区中的数据拷贝到 buf 中。

(注意协议接收到的数据可能大于 buf 的长度,所以在这种情况下需要调用几次 recv() 函数才能把 s

接收缓冲区的数据拷贝完。recv() 函数仅仅是拷贝数据,真正的接收数据是协议完成的。)

recv() 函数返回其实是拷贝的字节数,如果 recv() 函数在拷贝时出错,那么它返回 SOCKET_ERROR。

如果 recv() 函数在等待协议接收数据时网络中断,那么它返回 0。

sendto() 函数原型:

int sendto(

    SOCKET s,         // 指定发送端套接字描述符。

    const char *buf,  // 指明一个存放应用程序要发送数据的缓冲区。

    int len,     // 指明实际要发送的数据字节数。

    int flags,   // 一般置 0。

    const struct sockaddr* to,  // 为指向目的地址的指针。(表示目的机的 ip 和 port).

    int tolen    // 为 to 的长度。(一般赋值为 sizeof(sturct sockaddr).

);

recvfrom() 函数原型:

int recvfrom(

    SOCKET s,   // 指定接收端的套接字描述符。

    char *buf,  // 指明一个缓冲区,该缓冲区用来存放 recvfrom() 函数接收到的数据。

    int len,    // 指明 buf 的长度。

    int flags,  // 一般置 0.

    struct sockaddr *from,  // 为数据包的来源地址。

    int *fromlen   // 数据包的长度。

);
#include<stdio.h>
#include<winsock.h>
#pragma comment(lib,"ws2_32")
#define PORT 1234
int main(void)
{
SOCKET sockfd;
WSADATA ws;
char Buffer[MAX_PATH];
struct sockaddr_in their_addr; if(WSAStartup(MAKEWORD(, ), &ws) != 0)
{
exit(0);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
exit(0);
} their_addr.sin_family = AF_INET;
their_addr.sin_port = htons(PORT);
their_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); if (connect(sockfd, (struct sockaddr*)&their_addr, sizeof(struct sockaddr)) == SOCKET_ERROR)
{
closesocket(sockfd);
exit(0);
}
printf("input your msg:\n");
gets_s(Buffer);
send(sockfd, Buffer, MAX_PATH, );
closesocket(sockfd);
WSACleanup();
getchar();
return ;
}

客户端 SOCKET 编程的更多相关文章

  1. socket编程学习step1

    socket学习参考链接,赞一个:http://blog.csdn.net/hguisu/article/details/7445768 sockets(套接字)编程有三种,流式套接字(SOCK_ST ...

  2. socket编程中客户端常用函数

    1 常用函数 1.1   connect() int connect(int sockfd, const struct sockaddr *servaddr, socklen_taddrlen); 客 ...

  3. Windows Socket 编程_单个服务器对多个客户端简单通讯

    单个服务器对多个客户端程序: 一.简要说明 二.查看效果 三.编写思路 四.程序源代码 五.存在问题 一.简要说明: 程序名为:TcpSocketOneServerToMulClient 程序功能:实 ...

  4. 你得学会并且学得会的Socket编程基础知识(续)——Silverlight客户端

    本文将在这个案例的基础上,加入一个特殊场景,利用Silverlight来实现客户端.有的朋友可能会说,其实是一样的吧.请不要急于下结论,有用过Silverlight的朋友都有这种体会,很多在标准.NE ...

  5. Python Socket 网络编程 (客户端的编程)

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...

  6. 利用socket编程在ESP32上搭建一个TCP客户端

    通过之前http://www.cnblogs.com/noticeable/p/7636582.html中对socket的编程,已经可以知道如何通过socket编程搭建服务器和客户端了,现在,就在ES ...

  7. socket编程:客户端与服务器间的连接以及各函数的用法

    在认真的看UNP之前,一直被socket编程说的云里雾里,今天我要让大家从整天上认识socket编程,让我们知道socket编程的整个流程和各个函数的用法.这样:我们在写一些简单的socket编程时就 ...

  8. java 网络编程基础 TCP/IP协议:服务端ServerSocket;客户端Socket; 采用多线程方式处理网络请求

    1.Java中客户端和服务器端通信的简单实例 Java中能接收其他通信实体连接请求的类是ServerSocket,ServerSocket对象用于监听来自客户端的Socket连接,如果没有连接,它将一 ...

  9. java socket编程(li)

    一.网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输.在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以 ...

随机推荐

  1. XPath匹配含有指定文本的标签---contains的用法

    1.标签中只包含文字 <div> <ul id="side-menu"> <li class="active"> <a ...

  2. ssh免密码登陆(集群多台机器之间免密码登陆)

    1. 首先在配置hosts文件(每台机器都要) 进入root权限 vi /etc/hosts 添加每台机器的ip + 主机名,例如: 172.18.23.201 hadoop1 172.18.23.1 ...

  3. PHP5.6版本在Windows上安装redis扩展

    PHP使用redis扩展 一.php安装redis扩展   1.使用phpinfo()函数查看PHP的版本信息,这会决定扩展文件版本       2.根据PHP版本号,编译器版本号和CPU架构, 选择 ...

  4. win10下,打开oracle时出现 oracle initialization or shutdown in process 错误 的解决办法

    解决方法: 1)在dos窗口下输入:sqlplus /nolog 2)SQL>connect sys/sys as sysdba 提示:已连接. 3)SQL>shutdown normal ...

  5. 应用角度看kafka的术语和功能

    kafka的术语(Terminology) Topic 和Consumer Group Topic 每条发布到 Kafka 集群的消息都有一个类别,这个类别被称为 Topic.(物理上不同 Topic ...

  6. 移动端适配(手机端rem布局详解)

    1. 问题的引出 如果html5要适应各种分辨率的移动设备,应该使用rem这样的尺寸单位,同时给出了一段针对各个分辨率范围在html上设置font-size的代码: html{font-size:10 ...

  7. Kotlin基本语法和使用技巧

    基本语法 val value: String? = "HelloWorld" val name: String = getName() ?: return //如果是null就re ...

  8. 同时支持EF+Dapper的混合仓储,助你快速搭建数据访问层

    背景 17年开始,公司开始向DotNet Core转型,面对ORM工具的选型,当时围绕Dapper和EF发生了激烈的讨论.项目团队更加关注快速交付,他们主张使用EF这种能快速开发的ORM工具:而在线业 ...

  9. C#调用OpenCV开发简易版美图工具

    前言 在C#调用OpenCV其实非常简单,因为C#中有很多OPenCV的开源类库. 本文主要介绍在WPF项目中使用OpenCVSharp3-AnyCPU开源类库处理图片,下面我们先来做开发前的准备工作 ...

  10. Scala 占位符在REPL和Eclipse/IDEA中初始化变量问题

    占位符在REPL和Eclipse/IDEA中初始化变量问题: 占位符初始化,如果是局部变量,都会报错!只能在全局变量中使用! REPL: Eclipse: IDEA: 如果是类的属性,却就是对的.