TCP客户端程序
TCP客户端程序的函数调用顺序为:socket -> connect -> send/recv
socket、send和recv函数在TCP服务器程序中已经说过了,这里就不赘述了。
connect
connect函数的原型为:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd:socket函数返回的套接字描述符
addr:需要连接的IP地址和端口号,但一般传入struct sockaddr_in类型的指针
addrlen:传入sizeof(struct sockaddr_in)
struct sockaddr_in结构定义如下:
struct sockaddr_in{
sa_family_t sin_family; /* 地址族(Address Family)*/
uint16_t sin_port; /* 端口号 */
struct in_addr sin_addr; /* IP地址 */
char sin_zero[8]; /* 不使用,一般用0填充 */
};
struct in_addr结构定义如下:
struct in_addr{
in_addr_t s_addr; /* 32位的IP地址 */
};
同样的,对于TCP客户端而言,sin_family的值为AF_INET,sin_addr.s_addr写入服务器的IP地址,用inet_addr函数转换,sin_port写入服务器的端口,用htons函数转换。
connect函数成功返回0,失败返回-1。
connect成功之后便可用recv和send函数收发数据了,同样的,如果服务器断开连接,那么recv函数将不再阻塞,返回值为0,可以通过recv的返回值判断服务器是否断开连接。
不同的是调用recv和send时,TCP服务器程序传入的sockfd为accept返回的值,而TCP客户端程序传入的直接就是socket函数的返回值。
测试程序如下:
1 /**
2 * filename: tcp_client.c
3 * author: Suzkfly
4 * date: 2021-01-22
5 * platform: Ubuntu
6 * 配合windows的网络调试工具使用:
7 * 1、先保证windows与Ubuntu在同一网段且互相能ping通;
8 * 2、在windows下打开网络调试助手,选择协议类型为TCP Server,本地主机地址选
9 * 择windows的IP地址(或者windows下能和Ubuntu ping通的地址),端口号和
10 * 本文件中传入的端口号一致,接收设置和发送设置都选择ASCLL。
11 * 3、点击“打开”按钮。
12 * 4、运行Ubuntu下的TCP客户端程序;
13 * 5、连接成功后在网络调试助手上发送数据,在Ubuntu下的终端上能看到,
14 * 在Ubuntu下的终端上输入字符串按回车发送,在windows上的网络调试助手上也
15 * 能看到。
16 */
17 #include <stdio.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <string.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23
24 #define IP_ADDR "192.168.0.1" /* 服务器IP地址 */
25 #define PORT 24576 /* 服务器端口号 */
26
27
28 int main(int argc, const char *argv[])
29 {
30 int sock_fd = 0;
31 int ret = 0;
32 struct sockaddr_in serv_addr; /* 服务器地址 */
33 int pid = 0;
34 char buf[128] = { 0 };
35 int len = 0;
36
37 /* 创建TCP套接字 */
38 sock_fd = socket(AF_INET, SOCK_STREAM, 0);
39 if (sock_fd < 0) {
40 printf("socket failed\n");
41 return 0;
42 }
43
44 /* 与服务器建立连接 */
45 memset(&serv_addr, 0, sizeof(struct sockaddr_in));
46 serv_addr.sin_family = AF_INET;
47 serv_addr.sin_addr.s_addr = inet_addr(IP_ADDR); /* 服务器IP */
48 serv_addr.sin_port = htons(PORT); /* 服务器端口号 */
49 ret = connect(sock_fd,
50 (struct sockaddr *)&serv_addr,
51 sizeof(struct sockaddr_in));
52 if (ret == 0) {
53 printf("connect ok\n");
54 } else {
55 printf("connect failed\n");
56 close(sock_fd);
57 return 0;
58 }
59
60 pid = fork();
61
62 if (pid > 0) { /* 接收数据 */
63 while (1) {
64 memset(buf, 0, sizeof(buf));
65 len = recv(sock_fd, buf, sizeof(buf), 0);
66
67 if (len == 0) { /* 如果recv返回0,则表示远端断开连接 */
68 break;
69 }
70
71 printf("len = %d\n", len);
72 printf("data: %s\n", buf);
73 }
74 } else if (pid == 0) { /* 发送数据 */
75 while (1) {
76 memset(buf, 0, sizeof(buf));
77 scanf("%s", buf);
78 send(sock_fd, buf, strlen(buf), 0);
79 }
80 }
81 }
该程序在服务器断开连接的情况下,客户端不进行重连,而是直接退出程序。
该程序存在一个bug,就是发送数据和接收数据是通过不同的进程来控制的,而当服务器断开连接后,接收进程结束了,但发送进程还未结束。
网络调试助手设置如下:

TCP客户端程序的更多相关文章
- 初识Modbus TCP/IP-------------C#编写Modbus TCP客户端程序(一)
转自:http://blog.csdn.net/thebestleo/article/details/52269999 首先我要说明一下,本人新手一枚,本文仅为同样热爱学习的同学提供参考,有不 对的地 ...
- 【实验 1-1】编写一个简单的 TCP 服务器和 TCP 客户端程序。程序均为控制台程序窗口。
在新建的 C++源文件中编写如下代码. 1.TCP 服务器端#include<winsock2.h> //包含头文件#include<stdio.h>#include<w ...
- 初识Modbus TCP/IP-------------C#编写Modbus TCP客户端程序(二)
由于感觉上一次写的篇幅过长,所以新开一贴,继续介绍Modbus TCP/IP的初步认识, 书接上回 3).03(0x03)功能码--------读保持寄存器 请求与响应格式 这是一个请求读寄存器108 ...
- tcp客户端程序开发
https://www.cnblogs.com/python-No/ 话不多说,直接进入正题 一:客户端一共分为5大块: 1.创建客户端套接字 2.和服务端套接字建立连接 3.发送数据 4.接收发送 ...
- 29-ESP8266 SDK开发基础入门篇--编写TCP 客户端程序(Lwip RAW模式,非RTOS版,精简入门)
https://www.cnblogs.com/yangfengwu/p/11456667.html 由于上一节的源码长时间以后会自动断开,所以再做这一版非RTOS版的,咱直接用lua源码里面别人写的 ...
- 28-ESP8266 SDK开发基础入门篇--编写wifi模块TCP 客户端程序(官方API版,非RTOS版)
https://www.cnblogs.com/yangfengwu/p/11432795.html 注:这节实现的功能是WIFI模块作为TCP 客户端,连接咱的TCP服务器,然后实现透传 本来想着做 ...
- python网络编程--TCP客户端的开发
#导入socket模块 2 import socket 3 #参数说明 4 """ 5 socket类的介绍 6 创建客户端socket对象 7 socket.socke ...
- 网络编程之TCP客户端开发和TCP服务端开发
开发 TCP 客户端程序开发步骤 创建客户端套接字对象 和服务端套接字建立连接 发送数据 接收数据 关闭客户端套接字 import socket if __name__ == '__main__': ...
- JAVA笔记15__TCP服务端、客户端程序 / ECHO程序 /
/** * TCP:传输控制协议,采用三方握手的方式,保证准确的连接操作. * UDP:数据报协议,发送数据报,例如:手机短信或者是QQ消息. */ /** * TCP服务器端程序 */ public ...
随机推荐
- 【k8s实战一】Jenkins 部署应用到 Kubernetes
[k8s实战一]Jenkins 部署应用到 Kubernetes 01 本文主旨 目标是演示整个Jenkins从源码构建镜像到部署镜像到Kubernetes集群过程. 为了简化流程与容易重现文中效果, ...
- Autofac官方文档翻译--二、解析服务--2隐式关系类型
Autofac 隐式关系类型 Autofac 支持自动解析特定类型,隐式支持组件与服务间的特殊关系.要充分利用这些关系,只需正常注册你的组件,但是在使用服务的组件或调用Resolve()进行类型解析时 ...
- CSS中margin:auto什么意思?margin:auto属性的用法详解
我们都知道使用margin:auto可以让元素水平居中的.但你有没有想过使用margin:auto可以让元素水平居中的原因,要回答这个问题,我们首先需要看一下margin:auto的工作原理.auto ...
- LeetCode数组移除数组中目标元素等题目
一种自己解题,一种高赞解题 /** * 移除数组中目标元素,返回新数组长度 * @param nums * @param val * @return */ public int removeEleme ...
- 查看权限详情 将部门大类单据整合,将子类单据id去重合并
/** * 查看权限详情 * @param id 部门id * @return */ @GetMapping("getListInfo") public R getDetail(S ...
- [LeetCode]Minimum Moves to Equal Array Elements1,2
1.将每次n-1个数+1,转化为每次最大的数-1 public int minMoves(int[] nums) { /* 看了看答案 ,很巧妙,最后的结果肯定是把数组元素都加到一个相同的值, 也就是 ...
- 当layui与分页相遇--bootstrap何去何从
用了一段时间,感觉layui比bootstrap 方便了很多.在js操作上比bootstrap减少了许多的代码量. 今天遇到需要前台分页.当然,不是表格,如果是表格的话.使用yalui table和b ...
- Linux top命令在生产环境的妙用
top linux下的任务管理器 top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.top是一个动态显示过程,即可以通过用户按键来 ...
- Kubernetes官方java客户端之二:序列化和反序列化问题
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- CSS系列 (05):浮动详解
浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止.由于浮动框不在文档的普通流中,所以文档的普通流中的块框表现得就像浮动框不存在一样. -- W3C 文字环绕 float可以 ...