1、实现TCP的CS模型,即服务器客户端模型。
1.客户端和服务端的socket(),两边分别创建socket套接字。 客户端socket用于创建通信文件标识符,服务端的socket用于监听。 2.之后服务器和客户端都会使用bind函数将套接字绑定指定的端口,用于通信。 3.服务端将一开始的端口用listen绑定用于监听,等待客户端用于处理请求。 4.客户端用connect函数尝试进行tcp连接,发送syn包。服务端用accept回应,开始创建套接字用于处理该客户端请求,进行三次握手后建立tcp连接。 这个服务器accept每建立一个连接,都会建立一个专门处理这个连接的tcp 5.双方就可以用send和revc函数进行通信 6.结束后使用close关闭连接。
值得注意的是:服务器和客户端都需要在通信参数时,需要注意地址族是否相同或者兼容。客户端需要注意目标请求的ip和端口是否一致。
服务器
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/socket.h>
//指定服务器运行的端口
#define PORT 8080
//缓存的大小
#define BUFFER_SIZR 1024
int main(int argc, const char *argv[])
{
//一个监听请求的套接字,一个用于后续建立tcp请求的套接字
int server_fd,newserver_fd;
//用于定义通信协议的参数
struct sockaddr_in address;
int addlen=sizeof(address);
char buffer[BUFFER_SIZR]={0};
//创建监听套接字
if((server_fd=socket(AF_INET,SOCK_STREAM,0))==0){
perror("监听套接字创建失败");
exit(EXIT_FAILURE);
}
//设置IPV4协议
address.sin_family=AF_INET;
//设置为可接收任意接口
address.sin_addr.s_addr=INADDR_ANY;
//设定服务器运行端口
//htons:将本地运行数据转化成网络数据(与大小端有关)。
address.sin_port=htons(PORT);
//对套接字进行绑定
if(bind(server_fd,(struct sockaddr*)&address,sizeof(address))<0){
perror("绑定失败");
exit(EXIT_FAILURE);
}
//开始监听
if(listen(server_fd,3)<0){
perror("监听失败");
exit(EXIT_FAILURE);
}
//若接收到连接开始创建连接套接字
if((newserver_fd=accept(server_fd,(struct sockaddr*)&address,(socklen_t*)&addlen))<0){
perror("创建用户套接字失败");
exit(EXIT_FAILURE);
}
read(newserver_fd,buffer,BUFFER_SIZR);
printf("接收的数据为%s\n",buffer);
char str[]="这是服务器回复给你的消息";
send(newserver_fd,str,strlen(str),0);
close(server_fd);
close(newserver_fd);
return 0;
}
客户端
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/socket.h>
#define PORT 8080
#define BUFFER_SIZE 1024
#define IPADDRESS "127.0.0.1"
int main(int argc, const char *argv[])
{
//建立连接用的套接字
int sock=0;
//建立通信的参数结构体
struct sockaddr_in serv_addr;
char buffer[BUFFER_SIZE]={0};
//建立套接字
if((sock=socket(AF_INET,SOCK_STREAM,0))<0){
printf("套接字创建失败");
return -1;
}
//设置通信参数
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(PORT);
//用于将10.这样的十进制字符串转化成网络二进制
if(inet_pton(AF_INET,IPADDRESS,&serv_addr.sin_addr)<=0){
printf("转化失败");
return -1;
}
//尝试与服务器建立连接
if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0){
printf("连接建立失败");
return -1;
}
char str[]="来自客户端的消息";
send(sock,str,strlen(str),0);
read(sock,buffer,BUFFER_SIZE);
printf("客户端回复消息%s\n",buffer);
close(sock);
return 0;
}
2.UDP服务器中,使用connect函数,实现唯一的客户端与服务器通话。
这边需要注意的是,tcp使用的是字节流因此可以用send和recv函数,而udp使用的是报文,因此发送使用的是sendto和recvfrom进行数据的收发。
服务端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main(int argc, const char *argv[]) {
int sockid = 0;
char buffer[BUFFER_SIZE];
struct sockaddr_in seraddr, cliaddr;
socklen_t cliaddr_len;
if ((sockid = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("创建套接字失败");
exit(EXIT_FAILURE);
}
memset(&seraddr, 0, sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_addr.s_addr = INADDR_ANY;
seraddr.sin_port = htons(PORT);
if (bind(sockid, (const struct sockaddr *)&seraddr, sizeof(seraddr)) < 0) {
perror("绑定失败");
exit(EXIT_FAILURE);
}
// 接收来自客户端的消息
cliaddr_len = sizeof(cliaddr);
int n = recvfrom(sockid, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&cliaddr, &cliaddr_len);
buffer[n] = '\0';
printf("来自客户端: %s\n", buffer);
// 发送回复
sendto(sockid, "来自服务端", strlen("来自服务端"), 0, (const struct sockaddr *)&cliaddr, cliaddr_len);
close(sockid);
return 0;
}
客户端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main(int argc, const char *argv[]) {
int sockfd;
char buffer[BUFFER_SIZE];
struct sockaddr_in servaddr;
// 创建UDP套接字
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("套接字创建失败");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
// 设置服务器地址和端口
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
// 发送消息到服务器
sendto(sockfd, "来自客户端", strlen("来自客户端"), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));
printf("消息已发送。\n");
// 接收服务器回复
int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, NULL, NULL);
buffer[n] = '\0';
printf("来自服务端: %s\n", buffer);
close(sockfd);
return 0;
}