编写程序,实现客户端与服务器的无阻塞交互,提交程序源码、运行结果截图。
//server.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <pthread.h>
#define SERV_PORT 3333
//#define SERV_IP_ADDR "192.168.0.129"
#define BACKLOG 5
#define MAXSIZE 100
void* send_data(void* temp1)
{
int fd1=(int)temp1;
char sbuf[MAXSIZE];
while(1)
{
bzero(sbuf,MAXSIZE);
fgets(sbuf,MAXSIZE-1,stdin);
send(fd1,sbuf,strlen(sbuf),0);
}
return (void*)0;
}
void* recv_data(void* temp2)
{
int fd2=(int)temp2;
char rbuf[MAXSIZE];
int length;
while(1)
{
bzero(rbuf,MAXSIZE);
length = recv(fd2,rbuf,sizeof(rbuf),0);
rbuf[length] = '\0';
if(strncmp(rbuf,"close",5)==0)
{
printf("over\n");
break;
}
else
{
printf("%s\n",rbuf);
}
}
return (void*)0;
}
int main()
{
int sfd,sin_size,new_fd;
struct sockaddr_in serv_addr;//服务器地址信息
struct sockaddr_in client_addr;//客户端地址信息
//1.创建服务器端套接字sfd
sfd = socket(AF_INET,SOCK_STREAM,0);
/*优化: 允许绑定地址快速重用 */
int b_reuse = 1;
setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));
//2.将sfd与服务器端的IP地址和端口号绑定
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr = INADDR_ANY;
//serv_addr.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
bzero(&(serv_addr.sin_zero),8);
bind(sfd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr));
//3.开启监听
listen(sfd,BACKLOG);
while(1)
{
//4.与客户端建立连接
sin_size = sizeof(struct sockaddr_in);
new_fd = accept(sfd,(struct sockaddr*)&client_addr,&sin_size);
printf("Receive a connection from %s\n",inet_ntoa(client_addr.sin_addr));
//5.向客户端发送一条消息
send(new_fd,"Hello,you are conneceted!\n",26,0);
pthread_t thA,thB;
pthread_create(&thA,NULL,send_data,(void*)new_fd);
pthread_create(&thB,NULL,recv_data,(void*)new_fd);
pthread_join(thA,NULL);
pthread_join(thB,NULL);
close(new_fd);
}
return 0;
}
//client.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SERV_PORT 3333
#define MAXDATASIZE 100 /*每次最大数据传输量*/
int main(int argc, char *argv[])
{
int cfd, recvbytes; // cfd 数据传输socket
char buf[MAXDATASIZE];
struct hostent *host;
struct sockaddr_in serv_addr; //TCP/IP 协议的地址结构
if (argc < 2)
{
fprintf(stderr,"Please enter the server's hostname!\n");
exit(1);
}
if ((host=gethostbyname(argv[1]))==NULL)
//用域名或主机名获取IP 地址,可以直接输入IP 地址
{
perror("gethostbyname 出错!");
exit(1);
}
if ((cfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)//创建套接字
{
perror("socket 创建出错!");
exit(1);
}
serv_addr.sin_family=AF_INET; //表示TCP/IP 协议
serv_addr.sin_port=htons(SERV_PORT); /*16 位端口号,网络字节顺序*/
serv_addr.sin_addr = *((struct in_addr *)host->h_addr); /*32 位服务器IP 地址,网络字节顺序*/
bzero(&(serv_addr.sin_zero),8); /*保留*/
if (connect(cfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)// 建立连接, 连接的serv_addr 为保存服务器地址的结构体
{
perror("connect error!");
exit(1);
}
if ((recvbytes=recv(cfd, buf, MAXDATASIZE, 0)) ==-1) //接收数据
{
perror("recv 出错!");
exit(1);
}
buf[recvbytes] = '\0';
printf("Received: %s",buf);
close(cfd); //关闭socket
return 0;
}
PS:
结合线程基本知识,实现客户端与服务器的无阻塞交流。
(1)服务器代码清单
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <pthread.h>
#define SERVPORT 3333 //服务器监听端口号
#define BACKLOG 5 //最大同时连接请求数
#define MAXDATASIZE 100 /*每次最大数据传输量*/
void *senddata(void * arg)
{
int client_fd = (int)arg;
char sbuf[100];
while (1)
{
memset(sbuf, 0, sizeof(sbuf) / sizeof(char));
scanf("%s", sbuf);
/*子进程代码段*/
//往客户端发送消息
if (send(client_fd, sbuf, 26, 0) == -1)
{
perror("send\n");
}
if (strncmp(sbuf, "close", 5) == 0)
{
printf("server send close msg\n");
break;
}
}
return (void *)0;
}
void *recvdata(void *arg)
{
int client_fd = (int)arg;
char buf[MAXDATASIZE];
while (1)
{
memset(buf, 0, sizeof(buf) / sizeof(char));
if ((recv(client_fd, buf, sizeof(buf), 0)) == -1) {
perror("recv\n");
}
printf("server receives information %s \n ", buf);
if (strncmp(buf, "close", 5) == 0)
{
printf("will close client\n");
break;
}
}
return (void *)0;
}
int main()
{
int sockfd, client_fd, sin_size;//sockfd:服务器 socket,client_fd:客户端 socket
char buf[MAXDATASIZE];
struct sockaddr_in my_addr;//本机地址信息
struct sockaddr_in remote_addr;//客户端地址信息*
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket\n");
exit(1);
}
/*优化 4:允许绑定地址快速重用 */
int b_reuse = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(SERVPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;//表示监听任何地址
bzero(&(my_addr.sin_zero), 8);
//将本机地址与建立的套接字号进行绑定
if (bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1)
{
perror("bind\n");
exit(1);
}
//开始监听
if (listen(sockfd, BACKLOG) == -1)
{
perror("listen\n");
exit(1);
}
while (1)
{
sin_size = sizeof(struct sockaddr_in);
//接收客户端的连接
if ((client_fd = accept(sockfd, (struct sockaddr*)&remote_addr, &sin_size)) == -1)
{
perror("accept\n");
// continue;
}
printf("Receive a connection from %s\n", inet_ntoa(remote_addr.sin_addr));
pthread_t t1, t2;
pthread_create(&t1, NULL, senddata, (void *)client_fd);
pthread_create(&t2, NULL, recvdata, (void *)client_fd);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
close(client_fd);
printf("test main\n");
}
}
close(sockfd);
return 0;
(2)客户端代码清单
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SERVPORT 3333
#define MAXDATASIZE 100 /*每次最大数据传输量*/
void *senddata(void * arg)
{
int sockfd = (int)arg;
char sbuf[100];
while (1)
{
memset(sbuf, 0, sizeof(sbuf) / sizeof(char));
scanf("%s", sbuf);
/*子进程代码段*/
//往客户端发送消息
if (send(sockfd, sbuf, 26, 0) == -1)
{
perror("send\n");
}
if (strncmp(sbuf, "close", 5) == 0)
{
printf("client send close msg\n");
break;
}
}
return (void *)0;
}
void *recvdata(void *arg)
{
int sockfd = (int)arg;
char buf[MAXDATASIZE];
while (1)
{
memset(buf, 0, sizeof(buf) / sizeof(char));
if ((recv(sockfd, buf, sizeof(buf), 0)) == -1) {
perror("recv\n");
}
printf("client receives information %s \n ", buf);
if (strncmp(buf, "close", 5) == 0)
{
printf("client will close\n");
break;
}
}
return (void *)0;
}
int main(int argc, char *argv[])
{
int sockfd, recvbytes; // sockfd数据传输 socket
//char buf[MAXDATASIZE];
struct hostent *host;
struct sockaddr_in serv_addr; //TCP/IP协议的地址结构
if (argc < 2)
{
fprintf(stderr, "Please enter the server's hostname!\n");
exit(1);
}
if ((host = gethostbyname(argv[1])) == NULL)
//用域名或主机名获取 IP地址,可以直接输入 IP地址
{
perror("gethostbyname出错!");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)//创建套接字
{
perror("socket创建出错!");
exit(1);
}
serv_addr.sin_family = AF_INET; //表示 TCP/IP协议
serv_addr.sin_port = htons(SERVPORT); /*16位端口号,网络字节顺序*/
serv_addr.sin_addr = *((struct in_addr *)host->h_addr); /*32位服务器 IP地址,网络字节顺序*/
bzero(&(serv_addr.sin_zero), 8); /*保留*/
//建立连接,连接的 serv_addr为保存服务器地址的结构体
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect error!");
exit(1);
}
//printf("Receive a connection from %s\n",inet_ntoa(remote_addr.sin_addr));
pthread_t t1, t2;
pthread_create(&t1, NULL, senddata, (void *)sockfd);
pthread_create(&t2, NULL, recvdata, (void *)sockfd);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
close(sockfd);
printf("test main\n");
return 0;
}