1.复习代码
TCP:
socket.c
#include<myhead.h>
#define SER_PORT 6666 //服务器端口号
#define SER_IP "192.168.142.128" //服务器ip地址
int main(int argc, const char *argv[])
{
//1、创建套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
//参数1:表示ipv4的网络通信
//参数2:表示使用的是TCP通信方式
//参数3:表示默认使用一个协议
if(sfd == -1)
{
perror("socket error");
return -1;
}
printf("socket success, sfd = %d\n", sfd); //3
//将端口号快速重用
int opt = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt))==-1)
{
perror("setsockopt error");
return -1;
}
printf("setsockopt success\n");
//2、为套接字绑定ip地址和端口号
//2.1 填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //通信域
sin.sin_port = htons(SER_PORT); //端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //ip地址
//2.2 绑定工作
if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
//3、将套接字设置成被动监听状态
if(listen(sfd, 128)==-1)
{
perror("listen error");
return -1;
}
printf("listen success\n");
//4、阻塞等待客户端的连接请求
//4.1 定义变量用于接收客户端的信息
struct sockaddr_in cin; //用于接收地址信息
socklen_t addrlen = sizeof(cin); //用于接收长度
//4.2 接收连接
int newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen) ;
if(newfd == -1)
{
perror("accept error");
return -1;
}
printf("[%s:%d]: 已成功连接一个客户端\n", \
inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));
//5、数据收发
char buf[128] = "";
while(1)
{
//清空容器
bzero(buf, sizeof(buf));
//从客户端套接字中读取数据
int res = recv(newfd, buf, sizeof(buf), 0);
if(res == -1)
{
perror("read error");
return -1;
}else if(res == 0)
{
printf("客户端已经下线\n");
close(newfd); //关闭客户端套接字
break;
}
//正常收到客户端发来的消息
printf("[%s:%d] : %s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);
//对收到的消息进行一顿操作
//此处省略一万行代码
strcat(buf, "*_*");
//将消息回复给客户端
if(send(newfd, buf, strlen(buf), 0) == -1)
{
perror("发送error");
return -1;
}
printf("发送成功\n");
}
//6、关闭监听
close(sfd);
return 0;
}
user.c
#include<myhead.h>
#define SER_PORT 6666 //与服务器保持一致
#define SER_IP "192.168.142.128" //服务器IP地址
#define CLI_PORT 8888 //客户端端口号
#define CLI_IP "192.168.142.128" //客户端IP地址
int main(int argc, char const *argv[])
{
//1.创建用于通信的套接字文件描述符
int cfd = socket(AF_INET, SOCK_STREAM, 0);
if(cfd == -1)
{
perror("socket error");
return -1;
}
printf("cfd: %d\n", cfd);
//2. 绑定IP地址和端口号
//2.1 填充地址信息结构体
struct sockaddr_in cin;
cin.sin_family = AF_INET; //通信域
cin.sin_port = htons(CLI_PORT); // 端口号
cin.sin_addr.s_addr = inet_addr(CLI_IP); //IP地址
//2.2 绑定套接字
if(bind(cfd, (struct sockaddr *)&cin, sizeof(cin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
//3.连接到服务器
//3.1 填充服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //通信域
sin.sin_port = htons(SER_PORT); // 端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //IP地址
//3.2 连接服务器
if(connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
perror("connect error");
return -1;
}
printf("connect success\n");
//4. 数据收发
char buf[1024];
while(1)
{
printf("请输入:");
fgets(buf, sizeof(buf), stdin); //从终端获取字符串
buf[sizeof(buf)-1] = '\0';
// 向服务器发送数据
send(cfd, buf, strlen(buf), 0);
// 接收来自服务器的数据
// 先清空容器
memset(buf, 0, sizeof(buf));
// 接收来自服务器的数据并打印到终端
// 循环直到recv返回0,表示对方关闭套接字
// 若返回-1,表示出错,结束循环并打印出错信息
int ret = recv(cfd, buf, sizeof(buf), 0);
if(ret == -1)
{
perror("recv error");
break;
}
else if(ret == 0)
{
printf("server close\n");
break;
}
else
{
buf[ret] = '\0';
printf("server: %s\n", buf);
}
}
//5. 关闭套接字
close(cfd);
return 0;
}
运行结果:
UDP:
socket.c
#include<myhead.h>
#define SER_PORT 9999 //端口号
#define SER_IP "192.168.142.128" //IP地址
int main(int argc, char const *argv[])
{
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sfd == -1)
{
perror("socket");
return 1;
}
printf("sfd=%d\n", sfd);
//将端口号快速重用
int opt = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,&opt, sizeof(opt))==-1)
{
perror("setsockopt");
return 1;
}
printf("reuse success\n");
//2、为套接字绑定ip地址和端口号
//2.1 填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //通信域
sin.sin_port = htons(SER_PORT); //端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //ip地址
//2.2 绑定工作
if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
//3、数据收发
char buf[1024]="";
struct sockaddr_in cin; //接受对端地址信息
socklen_t addrlen = sizeof(cin); //接受地址长度
while(1)
{
//清空容器
memset(buf, 0, sizeof(buf));
//3.1 接收数据
recvfrom(sfd, buf, sizeof(buf), 0,(struct sockaddr*)&cin, &addrlen);
printf("收到信息为:%s\n", buf);
//处理数据
//省略
strcat(buf, "*_*");
if(sendto(sfd, buf, strlen(buf), 0, (struct sockaddr*)&cin, sizeof(cin)) == -1)
{
perror("发送错误");
return -1;
}
printf("发送成功\n");
}
//4.关闭文件描述符
close(sfd);
return 0;
}
user.c
#include<myhead.h>
#define SER_PORT 9999 //服务器端口号
#define SER_IP "192.168.142.128" //服务器ip地址
#define CLI_PORT 5555 //客户端端口号
#define CLI_IP "192.168.142.128" //客户端ip地址
int main(int argc, const char *argv[])
{
//1、创建用于通信的服务器套接字文件描述符
int cfd = socket(AF_INET, SOCK_DGRAM, 0);
if(cfd == -1)
{
perror("socket error");
return -1;
}
printf("sfd = %d\n", cfd); //3
//将端口号快速重用
int reuse = 1;
if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))==-1)
{
perror("setsockopt error");
return -1;
}
printf("端口号快速重用成功\n");
//2、为套接字绑定ip地址和端口号
//2.1 填充地址信息结构体
struct sockaddr_in cin;
cin.sin_family = AF_INET; //通信域
cin.sin_port = htons(CLI_PORT); //端口号
cin.sin_addr.s_addr = inet_addr(CLI_IP); //ip地址
//2.2 绑定工作
if(bind(cfd, (struct sockaddr*)&cin, sizeof(cin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
//3、数据收发
char buf[128] = "";
//填充服务器的地址信息结构体
struct sockaddr_in sin; //接受对端地址信息
sin.sin_family = AF_INET; //服务器的通信域
sin.sin_port = htons(SER_PORT); //服务器端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //服务器ip地址
while(1)
{
//从终端获取数据
printf("请输入>>>>");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = 0;
//将数据发送给服务器
sendto(cfd, buf, strlen(buf), 0, (struct sockaddr*)&sin, sizeof(sin));
printf("发送成功\n");
//清空容器
bzero(buf, sizeof(buf));
//接受服务器发来的消息
recvfrom(cfd, buf, sizeof(buf), 0, NULL, NULL);
printf("收到服务器消息为:%s\n", buf);
}
//4、关闭文件描述符
close(cfd);
return 0;
}
运行结果:
2.思维导图: