编写一个基于TCP协议的网络通信程序,一个客户程序,一个服务器程序。要求服务器通过socket连接后,接收客户端传来的用户名,判断为“liu”时,向客户端发送字符串“Hello,You are connected!”,否则,发送字符串“Sorry,you are not the user!”。客户端通过键盘输入用户名,发送到服务器,接收服务器发来的信息输出后结束。服务端显示客户端的IP地址。服务器程序为多进程并发方式(每一个连接创建一个子进程与客户端进行通信)处理多客户连接,并测试程序。
建立两台虚拟机配置IP地址:
192.168.228.100作为服务器端
192.168.228.101作为客户端
服务端代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXDATASIZE 100
#define SERVPORT 3333
#define BACKLOG 10
int main(){
int sockfd,client_fd,recvbytes;
char buf[MAXDATASIZE]; //用于接收数据的缓冲区
char user[] = "liu"; //定义用户名
struct sockaddr_in my_addr; //存储客户端地址
struct sockaddr_in remote_addr; //存储服务端地址
sockfd = socket(AF_INET, SOCK_STREAM, 0) ; //建立三元组
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(SERVPORT); //获取端口号
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//INADDR_ANY,转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的IP
bzero(&(my_addr.sin_zero),8); //给sockfd绑定端口
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1){
perror("bind error!");
exit(1);
}
//sockfd设立未监听端口
if (listen(sockfd, BACKLOG) == -1) {
perror("listen error!");
exit(1);
}
printf("wait for accept...\n");
while(1){
int sin_size = sizeof(struct sockaddr_in); //等待客户端连接
if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1) {
perror("accept error");
continue;
}
/*每次建立完整的socket连接之后,fork一个子进程来处理与客户端的会话,父进程继续等待其他客户端的连接*/
if (!fork()) {
printf("accept a connection from : %s\n", inet_ntoa(remote_addr.sin_addr));
sleep(10); //设置睡眠用来放大客户端同时访问的时间差
//接收客户端信息
if ((recvbytes = recv(client_fd, buf, MAXDATASIZE, 0)) ==-1) {
perror("receive error!");
exit(1);
}
buf[recvbytes] = '\0';
//执行服务器业务逻辑并反馈信息给客户端
if(strcmp(buf, user) == 0){
if (send(client_fd, "Hello,You are connected!", 26, 0) == -1){
perror("send error!");
exit(1);
}
}else{
if (send(client_fd, "Sorry,you are not the user!", 26, 0) == -1){
perror("send error!");
exit(1);
}
}
//业务逻辑完成或关闭子进程socket连接,结束子进程
close(client_fd);
exit(0);
}
close(client_fd); //关闭父进程socket连接
}
}
客户端代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SERVPORT 3333
#define SERVIP 192.168.228.100
#define MAXDATASIZE 100
int main(int argc, char *argv[])
{
int sockfd, recvbytes;
char buf[MAXDATASIZE]; //用于发送数据的缓冲区
struct hostent *host; //用来接收服务主机信息
struct sockaddr_in serv_addr;
if (argc < 2){
fprintf(stderr,"Please enter the username!\n");
exit(1);
}
//获取服务器主机信息
if((host=gethostbyname(SERVIP)) == NULL) {
herror("gethostbyname error!");
exit(1);
}
//建立客户端三元组
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror("socket create error!");
exit(1);
}
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(SERVPORT);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8); //置字节字符串my_addr.sin_zero的前n个字节为零且包括‘\0’
//向服务器发送连接
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1){
perror("connect error!");
exit(1);
}
//发送数据给服务器
if (send(sockfd, argv[1], 26, 0) == -1){
error("send error!");
exit(0);
}
//接收服务器发送的信息
if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1){
perror("receive error!");
exit(1);
}
buf[recvbytes] = '\0';
//输出服务器发送的信息
printf("information: %s\n",buf);
close(sockfd);
}
演示:
开启服务器
单用户:
客户端连接输入错误用户名,连接失败
客户端内连接输入正确用户名,连接成功
客户端连接成功后,服务端接收到的反馈信息
多用户:
在客户机下开启两个会话同时执行客户端程序
在服务端设置当一个用户连接成功是睡眠5s(放大同时连接的时间差,模拟多用户同时连接)