❤️ 专栏简介 :网络通信和Socket编程是Linux C/C++服务器开发的基础。本专栏从最基础的内容开始学习网络通信和socket编程的相关内容,循序渐进的掌握网络通信的和socket编程的相关知识。主要内容包括网络通信与socket编程概述、socket通信模型、套接字概述、socket通信交互流程以及Socket通信中各个函数的实现以及功能等。
☀️ 专栏适用人群 :适用于具备基础 Linux 知识的并想从零开始学习网络通信和Socket编程初学者;以及想学习Linux上c/c++服务器开发的朋友们。
🌙专栏特点:通俗易懂、图文并茂、非常详细;
🌴 专栏说明 :如果文章知识点有错误的地方,欢迎大家随时在文章下面评论,我会第一时间改正。让我们一起学习,一起进步。
🍄 专栏地址:https://blog.csdn.net/anchenliang_1002/category_11919076.html
本节我们来通过一个实际的实例来演示socket通信;Socket通信要有服务端和客户端;本节我们先实现一个网络通信中的客户端。
一、客户端的流程
客户端的实现流程如下:
socket()-->connect()-->read()/write()-->close()
简单介绍一下各个函数,详细的介绍会在以后学习。
socket()用来创建套接字
connect()//请求连接,类似于打电话过程中的“拨打”功能。
read()/write()//进行数据交换
close()//断开连接
二、客户端源码实现
首先,我们在socket
文件夹下然后创建服务端源文件:
touch client.c
vim client.c
然后将以下代码复制进去
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVER_PORT 666 //定义服务器端口号
int main(int argc, char *argv[])
{
int sock_send;//定义客户端的socket,对应第一节写信中的例子中的写信人的信箱
char *message = NULL;//用来存放客户端要发送的消息
struct sockaddr_in servaddr;//用于存放客户端ip和端口;对应第一节写信例子中的发件人的标签
int n;
char buf[2048];//用于存放读取的socket中的数据
if(argc != 2)//出错处理
{
fputs("usage:./client message \n",stderr);
exit(1);//结束进程并返回1
}
message = argv[1];//获取输入的第一个参数,也就是我们客户端要向服务端请求的消息
printf("message: %s \n",message);
//创建套接字,对应于第一节写信例子中发信方的“信箱”
//AF_INET代表使用协议族IPV4;
//SOCK_STRESAM表示使用TCP协议;
sock_send = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr,'\0', sizeof(servaddr));//将servaddr清零
//指定协议族为AF_INET,IPV4
servaddr.sin_family = AF_INET;
//指定接收方的ip为127.0.0.1,即本机回环地址;对应第一节写信例子中的收信方的地址
inet_pton(AF_INET,"127.0.0.1", &servaddr.sin_addr);
//指定接收方的端口为666;对应第一节写信例子中的收信方的姓名小明
servaddr.sin_port = htons(SERVER_PORT);
//建立本机与sock_send套接字之间的连接
connect(sock_send,(struct sockaddr *)&servaddr, sizeof(servaddr));
//将要发送的消息即message写进sock_send里;对应第一节写信的例子就是在信中写内容
write(sock_send, message, strlen(message));
//读取sock_send返回的消息,并将返回的消息写进buf里。
n = read(sock_send, buf, sizeof(buf)-1);
if( n > 0 )
{
buf[n] = '\0';
printf("receive: %s \n", buf);
}
else
{
perror("error !!!");
}
printf("finished. \n");
close(sock_send);//关闭发送套接字
return 0;
}
三、源码解释
客户端负责向服务端发送请求消息。对应第一节写信中的例子,客户端就是写信人;
第13行代码int sock_send;
表示声明一个客户端的socket;对应第一节写信中的例子中的写信人的信箱;
第17行struct sockaddr_in servaddr;
表示定义servaddr,用于存放客户端ip和端口;对应第一节写信例子中的发件人的标签。
第37行sock_send = socket(AF_INET, SOCK_STREAM, 0);
表示创建套接字,对应于第一节写信例子中发信方的“信箱”;AF_INET代表使用协议族IPV4;SOCK_STRESAM表示使用TCP协议;
第45行inet_pton(AF_INET,"127.0.0.1", &servaddr.sin_addr);
表示指定接收方的ip为127.0.0.1,即本机回环地址;对应第一节写信例子中的收信方的地址。
第48行servaddr.sin_port = htons(SERVER_PORT);
表示指定接收方的端口为666;对应第一节写信例子中的接收方的姓名即小明。
第51行connect(sock_send,(struct sockaddr *)&servaddr, sizeof(servaddr));
表示建立本机与sock_send套接字之间的连接。
第54行write(sock_send, message, strlen(message));
表示//将要发送的消息即message写进sock_send里;对应第一节写信的例子就是在信中写内容。
第57行n = read(sock_send, buf, sizeof(buf)-1);
表示//读取sock_send返回的消息,并将返回的消息写进buf里。
所以通过这代码我们会向服务端发送一段消息,并接受服务端回复给客户端的消息,将其打印出来。
四、运行结果
我们对client进行编译,
gcc client.c -o client
然后启动服务端:
./server
然后启动客户端,并发送一段消息给服务端:
./client "this is a test"
结果如下:
首先在服务端,收到了客户端发来消息,并将这段消息发回给了客户端,如下图所示:
然后我们看一下客户端这边的内容:
可以看到,客户端发了“this is a test”给服务端,并且收到了服务端发回的“this is a test”。