目录
一.创建一个socket文件夹用来存放编写的服务器端和客户端程序
二.编写服务器端代码
三.编写客户端代码
四.编译c语言程序
五.断开连接
六.可能涉及到的一些没接触过的知识点
一.创建一个socket文件夹用来存放编写的服务器端和客户端程序
(我系统里的文件在temp/socket$文件夹中)
二.编写服务器端代码
vim server.c
在server.c中编写的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>//提供IP地址转换函数
int main()
{
//1.创建监听的套接字
int fd = socket(AF_INET,SOCK_STREAM, 0);
if (fd == -1)
{
perror("socket");//perror(s) 用来将上一个函数发生错误的原因输出到标准设备,参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串。
return -1;
}
//2.绑定本地的IP port
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;//地址族协议
saddr.sin_port = htons(9999);//端口必须转换成大端
saddr.sin_addr.s_addr = INADDR_ANY;//指定IP地址(INADDR_ANY泛指本机的意思,也就是表示本机的所有IP)
int ret = bind(fd, (struct sockaddr*)&saddr, sizeof(saddr));
if (ret == -1)//绑定失败 返回-1
{
perror("bind");
return -1;
}
//3设置监听
ret = listen(fd, 128);
if (ret == -1)
{
perror("listen");
return -1;
}
//4阻塞并等待客户端的连接
struct sockaddr_in caddr;
int addrlen = sizeof(caddr);
int cfd = accept(fd, (struct sockaddr*)&caddr,&addrlen );
if (cfd == -1)
{
perror("accept");
return -1;
}
//连接建立成功,打印客户端的IP和端口信息
char ip[32];
printf("客户端的ip:%s,端口:%d\n",
inet_ntop(AF_INET, &caddr.sin_addr.s_addr, ip, sizeof(ip)), ntohs(caddr.sin_port));//网络字节序转换为主机字节序
//5.通信
while (1)
{
//接收数据
char buff[1024];
int len = recv(cfd, buff, sizeof(buff), 0);
if (len > 0)
{
printf("client say: %s\n", buff);
send(cfd, buff, len, 0);
}
else if (len == 0)
{
printf("客户端已经断开了连接...\n");
break;
}
else
{
perror("recv");
break;
}
}
//关闭文件描述符
close(fd);
close(cfd);
return 0;
}
三.编写客户端代码
vim client.c
在client中编写的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>//提供IP地址转换函数
int main()
{
//1.创建通信的套接字
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
perror("socket");//perror(s) 用来将上一个函数发生错误的原因输出到标准设备,参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串。
return -1;
}
//2.连接服务器IP port
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;//地址族协议
saddr.sin_port = htons(9999);//端口必须转换成大端
inet_pton(AF_INET, "192.168.122.1 ", &saddr.sin_addr.s_addr);
int ret = connect(fd, (struct sockaddr*)&saddr, sizeof(saddr));
if (ret == -1)//连接失败 返回-1
{
perror("connect");
return -1;
}
int number = 0;
//3.通信
while (1)
{
//发送数据
char buff[1024];
sprintf(buff, "你好,hello ,world ,%d...\n", number++);
send(fd, buff, strlen(buff) + 1, 0);
//接收数据
memset(buff, 0, sizeof(buff));
int len = recv(fd, buff, sizeof(buff), 0);
if (len > 0)
{
printf("server say: %\n", buff);
}
else if (len == 0)
{
printf("服务器端已经断开了连接...\n");
break;
}
else
{
perror("recv");
break;
}
sleep(1);
}
//关闭文件描述符
close(fd);
return 0;
}
四.编译c语言程序
[itliang@localhost socket]$ gcc client.c -o client
[itliang@localhost socket]$ gcc server.c -o server
运行server.c程序,先运行服务器端再运行客户端
运行client.c程序,至此客户端与服务器端建立通信,客户端收到服务器端消息,并输出“你好,hello,world”
服务器端收到客户端消息,并输出“你好,hello,world”
五.断开连接
当服务器端断开连接时,客户端会显示“服务器端已经断开了连接”
当客户端断开连接时,服务器端会显示“客户端已经断开了连接”
六.可能涉及到的一些没接触过的知识点
perror(s)函数
用来将上一个函数发生错误的原因输出到标准设备(stderr)。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串。
sockaddr_in在头文件#include<netinet/in.h>或#include <arpa/inet.h>
中定义,该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中,如下:
GCC 是 Linux 下的编译工具集,是 GNU Compiler Collection 的缩写,包含 gcc、g++ 等编译器。这个工具集不仅包含编译器,还包含其他工具集,例如 ar、nm 等。
GCC 工具集不仅能编译 C/C++ 语言,其他例如 Objective-C、Pascal、Fortran、Java、Ada 等语言均能进行编译。GCC 在可以根据不同的硬件平台进行编译,即能进行交叉编译,在 A 平台上编译 B 平台的程序,支持常见的 X86、ARM、PowerPC、mips 等,以及 Linux、Windows 等软件平台。
有些纯净版的 Linux 默认没有 gcc 编译器,需要自己安装,在线安装步骤如下:
# 安装软件必须要有管理员权限
# ubuntu
$ sudo apt update # 更新本地的软件下载列表, 得到最新的下载地址
$ sudo apt install gcc g++ # 通过下载列表中提供的地址下载安装包, 并安装
# centos
$ sudo yum update # 更新本地的软件下载列表, 得到最新的下载地址
$ sudo yum install gcc g++ # 通过下载列表中提供的地址下载安装包, 并安装
gcc 安装完毕之后,可以查看版本:
# 查看 gcc 版本
$ gcc -v
$ gcc --version
# 查看 g++ 版本
$ g++ -v
$ g++ --version
编译:
# 参数 -c 是进行文件的汇编, 汇编之前的两步会自动执行
$ gcc test.c -c -o app.o