文章目录
实验环境:
cnetos7
ip:192.168.43.168
实验内容与步骤
PART 1 程序理解 (socket实现服务器端-客户端的TCP通信)
服务器代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVER_PORT 6000 //端口号可自己设置
#define SERVER_IP "192.168.126.128" // IP 地址请自己根据实际情况设置
int listen_fd = -1;
void signal_handler(int arg)
{
printf("close listen_fd(signal = %d)\n", arg);
close(listen_fd);
exit(0);
}
int main(int argc, const char *argv[])
{
int new_fd = -1;
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t saddrlen = sizeof(server);
socklen_t caddrlen = sizeof(client);
signal(SIGINT, signal_handler);
memset(&server, 0, sizeof(server));
memset(&client, 0, sizeof(client));
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0)
{
printf("socket error!\n");
return -1;
}
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
server.sin_addr.s_addr = inet_addr(SERVER_IP);
if (bind(listen_fd, (struct sockaddr *)&server, saddrlen) < 0)
{
printf("bind error!\n");
return -1;
}
if (listen(listen_fd, 5) < 0)
{
printf("listen error!\n");
return -1;
}
char rbuf[256] = {0};
int read_size = 0;
while (1)
{
new_fd = accept(listen_fd, (struct sockaddr *)&client, &caddrlen);
if (new_fd < 0)
{
perror("accept");
return -1;
}
printf("new client connected.IP:%s,port:%u\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
while (1)
{
read_size = read(new_fd, rbuf, sizeof(rbuf));
if (read_size < 0)
{
printf("read error!\n");
continue;
}
else if (read_size == 0)
{
printf("client (%d) is closed!\n", new_fd);
close(new_fd);
break;
}
printf("recv:%s\n", rbuf);
}
}
close(listen_fd);
return 0;
}
客户端代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVER_PORT 6000 // 端口
#define SERVER_IP "192.168.126.128" //服务器IP地址
int main(int argc, const char *argv[])
{
int connect_fd = -1;
struct sockaddr_in server;
socklen_t saddrlen = sizeof(server);
memset(&server, 0, sizeof(server));
connect_fd = socket(AF_INET, SOCK_STREAM, 0);
if (connect_fd < 0)
{
printf("socket error!\n");
return -1;
}
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
server.sin_addr.s_addr = inet_addr(SERVER_IP);
if (connect(connect_fd, (struct sockaddr *)&server, saddrlen) < 0)
{
printf("connect failed!\n");
return -1;
}
char buf[256] = {0};
while (1)
{
printf(">");
fgets(buf, sizeof(buf), stdin);
if (strcmp(buf, "quit\n") == 0)
{
printf("client will quit!\n");
break;
}
write(connect_fd, buf, sizeof(buf));
}
close(connect_fd);
return 0;
}
运行结果:
打开第3个终端窗口,运行client窗口,观察程序运行结果。分析:服务器端能同时响应两个客户端的连接请求吗?
打开第三个窗口运行client后结果:
服务器并没有接收到第二个客户端发来的信息。
但是在这个时候将第一个客户端的连接断开后服务器接收到了第二个客户端发来的信息。
PART 2 程序实现
PART 1 中实现的功能是客户端向服务器端发送信息,服务器端接收到信息后显示出来,在理解上述程序的基础上,对程序功能进行扩展,实现如下功能:
(1)服务器端接收到信息后,进行简单的加密处理,然后将加密之后的字符串发回给客户端,客户端将其显示出来。 加密策略为:如果字符为英文字符,则进行大小写转换,如果是数字字符,则将相应的数字加6再取个位数,如果是其他字符,则保留原样。如服务器接收到的字符串为:A1b2D9#6,则加密之后的字符串为:a7B8d5#2
(2)如果服务器端接收的字符串是"time",则不需要进行加密,而是将系统时间发送给客户端,客户端显示收到的信息。
服务器代码:
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVER_PORT 6000 //端口号可自己设置
#define SERVER_IP "192.168.43.168" // IP 地址请自己根据实际情况设置
int listen_fd = -1; //socket描述符
void signal_handler(int arg) //信号处理,遇到ctrl + c退出
{
printf("close listen_fd(signal = %d)\n", arg);
close(listen_fd);
exit(0);
}
//获得系统时间
char* showTime() {
time_t timer = time(NULL);
char* showTime = asctime(localtime(&timer));
return showTime;
}
//特定的加密操作
void endecrypt(char *rbuf){
char *p = rbuf;
while (*p != '\0'){
if((*p >= 'a' && *p <= 'z')) {
*p = *p - 32;
}else if(*p >= 'A' && *p <= 'Z'){
*p = *p + 32;
}else if(*p >= '0' && *p <= '9'){
*p = (((*p - '0') + 6) % 10) + '0';
}
p++;
}
}
int main(int argc, const char *argv[]) {
int new_fd = -1; //socket新描述符
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t saddrlen = sizeof(server);
socklen_t caddrlen = sizeof(client);
signal(SIGINT, signal_handler);
memset(&server, 0, sizeof(server)); //初始化
memset(&client, 0, sizeof(client));
listen_fd = socket(AF_INET, SOCK_STREAM, 0); //创建socket,并更新socket描述符
if (listen_fd < 0) //如果socket创建失败则退出
{
printf("socket error!\n");
return -1;
}
server.sin_family = AF_INET; //设置协议类型为IPv4
server.sin_port = htons(SERVER_PORT); //设置端口
server.sin_addr.s_addr = inet_addr(SERVER_IP); //将服务器点分十进制ip转换为32位二进制网络字节序并设置
if (bind(listen_fd, (struct sockaddr *) &server, saddrlen) < 0) //绑定一个端口号和ip,使套接口与指定的端口号和ip相关联
{
printf("bind error!\n");
return -1;
}
if (listen(listen_fd, 5) < 0) //设置监听,最大连接请求数为5
{
printf("listen error!\n");
return -1;
}
char rbuf[256] = {0}; //缓冲区
int read_size = 0;
while (1) {
new_fd = accept(listen_fd, (struct sockaddr *) &client, &caddrlen); //接受服务请求,并设置最新socket描述符
if (new_fd < 0) {
perror("accept");
return -1;
}
printf("new client connected.IP:%s,port:%u\n", inet_ntoa(client.sin_addr),ntohs(client.sin_port)); //打印出ip和端口提示
while (1) //对接受到的数据进行处理
{
read_size = read(new_fd, rbuf, sizeof(rbuf)); //进行读操作,read_size存储数据大小
if (read_size < 0) {
printf("read error!\n");
continue;
} else if (read_size == 0) {
printf("client (%d) is closed!\n", new_fd);
close(new_fd);
break;
}
printf("----------------receive---------------\n");
printf("%s\n", rbuf);
printf("----------------over!-----------------\n");
//printf("i want to test:%d len=%d\n",strncmp(rbuf, "time\n",strlen(rbuf)),strlen(rbuf));
if (!strncmp(rbuf, "time\n",strlen(rbuf) - 1)) { //这里-1是将换行符去掉
/*
* 当fgets将输入写入rbuf时,会包括换行符
*/
//printf("this\n");
//char *time = showTime();
//rbuf = showTime();
//printf("the time:%s\n sizeof_time:%d",time, sizeof(time));
strcpy(rbuf,showTime()); //将系统时间复制到rbuf
write(new_fd, rbuf, sizeof(rbuf)); //数据发送
}else{
// printf("endecrypt");
endecrypt(rbuf);
// printf("encrypt mess:%s\n",rbuf);
write(new_fd,rbuf,sizeof(rbuf));
}
printf("---------------i had send it over---------------\n");
}
}
printf("i will cloes\n");
close(listen_fd);
return 0;
}
客户端代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVER_PORT 6000 // 端口
#define SERVER_IP "192.168.43.168" //服务器IP地址
int main(int argc, const char *argv[]) {
int connect_fd = -1;
struct sockaddr_in server;
socklen_t saddrlen = sizeof(server);
memset(&server, 0, sizeof(server));
connect_fd = socket(AF_INET, SOCK_STREAM, 0);
if (connect_fd < 0) {
printf("socket error!\n");
return -1;
}
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
server.sin_addr.s_addr = inet_addr(SERVER_IP);
if (connect(connect_fd, (struct sockaddr *) &server, saddrlen) < 0) {
printf("connect failed!\n");
return -1;
}
char buf[256] = {0};
while (1) {
printf(">");
fgets(buf, sizeof(buf), stdin);
if (strcmp(buf, "quit\n") == 0) {
printf("client will quit!\n");
break;
}
write(connect_fd, buf, sizeof(buf));
printf("-----------------have a message from server----------------\n");
char sbuf[256] = {0};
int read_size = read(connect_fd, sbuf, sizeof(sbuf));
if (read_size < 0) {
printf("read error!\n");
continue;
} else if (read_size == 0) {
printf("mess over!\n");
}
printf("messg:%s\n", sbuf);
printf("---------------------messg over!---------------------------\n");
}
close(connect_fd);
return 0;
}
运行结果: