服务器:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
//#include <stdlib.h>
#include <string.h>
#include <unistd.h>//_exit
#include <pthread.h>
#define SERVPORT 5000
//线程与进程相比:不关listenfd,将connfd传下来
//线程对公共区域可以用,线程不存在继承问题,这里不是公共区域
//创建进程需要分配空间,对系统资源消耗比较大,线程用的进程的空间,节俭系统资源
void * client_chart(void * arg)
{
int connfd,n;//
char msg[1000];
socklen_t clilen;
struct sockaddr_in cliaddr;
clilen = sizeof(cliaddr);
connfd =*((int *)arg);//得到主线程传给我的与客户端连接的套接口
for(;;)
{
int i;
n = recvfrom(connfd,msg,1000,0,(struct sockaddr*)&cliaddr,&clilen);
//n是实际接收的字节数
//sendto(connfd,msg,n,0,(struct sockaddr*)&cliaddr,sizeof(cliaddr));
if(0 == n)
{
printf("client offline!\n");
pthread_exit(NULL);//线程结束
}
printf("-------------------\n");
msg[n] = '\0';
printf("received the following:\n");
printf("%s\n",msg);//数组的表示方式
printf("-------------------------\n");
for(i = 0;i < n;i++)
{
msg[i] = toupper(msg[i]);
}
sendto(connfd,msg,n,0,(struct sockaddr*)&cliaddr,sizeof(cliaddr));
}
close(connfd);
return NULL;
}
int main()//线程——TCP的并发服务器
{
int listenfd,connfd,n;//套接口,返回的字节数
struct sockaddr_in servaddr,cliaddr;//服务器、客户端的地址
socklen_t clilen;//客户端地址的长度,类型独特
char msg[1000];//发送消息的缓冲区
pid_t pid;
int ret;
pthread_t tid;
listenfd = socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));//缓冲区取服务器的地址,
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERVPORT);//同一个服务器,地址相同
bind(listenfd,(struct sockdaddr *)&servaddr,sizeof(servaddr));
//监听套接口
listen(listenfd,100);
while(1)//连接每一个客户端
{
clilen = sizeof(cliaddr);//为后面的客户端地址服务的
connfd = accept(listenfd,(struct socdaddr*)&cliaddr,&clilen);
//全局变量,只有一个,容易被覆盖
//但connfd连接套接口是在监听到一个客户端后,就需要生产一个新的套接口
ret = pthread_create(&tid,NULL,(void *)client_chart,(void*)&connfd);
/*#if 0
if((pid = fork()) == 0)//子进程里完成了和客户端会话的所有任务
{
//close(listenfd);线程对公共区域可以用,线程不存在继承问题,这里不是公共区域
//创建进程需要分配空间,对系统资源消耗比较大,线程用的进程的空间,节俭系统资源
for(;;)//只要输入有效的字符串,就可以多次发送、接收
{
int i;
}
close(connfd);//关闭会话的连接套接口
//_exit(0);
}
#endif*/
}
close(listenfd);
return 0;
}
客户端:
#include <stdio.h>
#include <sys/socket.h>//超级口都需要
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#define SERVPORT 5000
//客户端写程序时,运行的进程拆成两个线程(网上读、网上写分离)
//只有一个进程时,scanf就要挂起
//输入信息和接收信息是并行的
int main(int argc,char ** argv)//获取别人的ip地址可以从命令行里输进去
{
int sockfd,n;
struct sockaddr_in servaddr,cliaddr;//结构体加&,才变成指针,变成后"&servaddr"代表结构体的首地址
char sendline[1000];//发送缓冲区大小
char recvline[1000];//你们跟指针有什么关系,你们需要吗?他们是有自己空间的,数组名代表数组的首地址
if(argc != 2)//如果命令行里没有输入服务器的地址
{
printf("usage:server address!\n");
exit(0);//不是出错,是正常退出,程序命令正确,输入不符合规范
//输入了服务器的地址,客户端可以连接服务器
}
sockfd = socket(AF_INET,SOCK_STREAM,0);//创建客户端的套接口
bzero(&servaddr,sizeof(servaddr));//配置服务器的地址
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERVPORT);
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
//服务器连接客户端时可以连接到客户端的任意网卡上
//客户机连接时要有具体的服务器某网卡的地址
connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
while(fgets(sendline,1000,stdin) != NULL)//stdin是标准输入模型
//输入scanf,从stdin中获得的值放到sendline缓冲区中
//只要有数据,不停地发送、接收信息
{
sendto(sockfd,sendline,strlen(sendline),0,
(struct sockaddr *)&servaddr,sizeof(servaddr));
//实际发送的字节数,与第三个形参有关
n = recvfrom(sockfd,recvline,1000,0,NULL,NULL);
//第二个形参void*可以不是指针
//实际接收的字节数,与第六个形参有关
recvline[n] = '\0';
fputs(recvline,stdout);//输出printf,从recvline缓冲区中显示到stdout中
}
close(sockfd);
return 0;
}
终端:
?
|