您的位置:首页 > 理论基础 > 计算机网络

Linux网络编程——服务器与客户端

2019-08-19 20:31 1461 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/yiluo9918/article/details/99546916

文章目录

1 单连接C/S

简单实现单连接的服务器与客户端,服务器处理客户端的字符为大写返回给客户端

  • 服务器端
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <ctype.h>
#include <arpa/inet.h>
#define SERV_PORT 6666
#define SERV_IP "127.0.0.1"
int main()
{
int lfd,cfd;
char buf[BUFSIZ],clie_IP[BUFSIZ];
int n;
struct sockaddr_in serv_addr, clie_addr;
socklen_t clie_addr_len;
/*创建一个socket 指定IPv4协议族 TCP协议*/
lfd = socket(AF_INET, SOCK_STREAM, 0);

/*初始化一个地址结构 man 7 ip 查看对应信息*/
bzero(&serv_addr, sizeof(serv_addr));           //将整个结构体清零
serv_addr.sin_family = AF_INET;                 //选择协议族为IPv4
serv_addr.sin_port = htons(SERV_PORT);          //绑定端口号
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY这个宏可以自动转换为本地有效的IP
/*绑定服务器地址结构*/
bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));

listen(lfd, 128);   //同一时刻允许向服务器发起链接请求的数量
printf("wait for client connect ...\n");

clie_addr_len = sizeof(clie_addr);/*获取客户端地址结构大小*/

/*参数1是sfd; 参2传出参数, 参3传入传出参数, 全部是client端的参数*/
cfd = accept(lfd, (struct sockaddr *)&clie_addr, &clie_addr_len);
printf("client IP:%s\tport:%d\n",
inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP, sizeof(clie_IP)),
ntohs(clie_addr.sin_port));
while(1){
/*读取客户端发送数据*/
n = read(cfd, buf, sizeof(buf));
//小写转大写发送给客户端
for(i=0;i<n;i++)
buf[i] = toupper(buf[i]);
write(cfd, buf,n);
}
close(lfd);
close(cfd);
return 0;
}
  • 客户端
client.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define SERV_IP "127.0.0.1"
#define SERV_PORT 6666
int main()
{
int sfd,serv_addr_len,cfd;
char buf[BUFSIZ];
int n;

sfd = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in serv_addr;//服务器IP+port
bzero(&serv_addr, sizeof(serv_addr));//清零
serv_addr.sin_family = AF_INET;
inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);//IP字符串转换为网络字节序 参3:传出参数
serv_addr.sin_port = htons(SERV_PORT);//端口号转网络字节序

connect(sfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr));
while(1){
fgets(buf, sizeof(buf), stdin);/*从标准输入获取数据*/
write(sfd, buf, strlen(buf));/*将数据写给服务器*/
len = read(sfd, buf, sizeof(buf));/*从服务器读回转换后数据*/
write(STDOUT_FILENO, buf,len); /*写至标准输出*/
}
close(sfd);
return 0;
}

2 多进程并发C/S

  • 服务器端(多进程并发)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <strings.h>
#include <ctype.h>
#define SERV_PORT 8888
void wait_child(int signo){
while(waitpid(0,NULL,WNOHANG)>0);//子进程回收
return ;
}
int main()
{
pid_t pid;
int lfd,cfd;
struct sockaddr_in serv_addr,clie_addr;
socklen_t clie_addr_len;
char buf[BUFSIZ],clie_IP[BUFSIZ];
int n,i;

lfd = socket(AF_INET, SOCK_STREAM,0);
bzero(&serv_addr, sizeof(serv_addr));//	清零
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//inet_pton(AF_INET,"192.168.43.1",serv_addr.sin_addr.s_addr);
bind(lfd,(struct sockaddr *)&serv_addr, sizeof(serv_addr));
listen(lfd,128);

while(1){//接活,处理新到来的连接
clie_addr_len = sizeof(clie_addr);
cfd = accept(lfd, (struct sockaddr *)&clie_addr, &clie_addr_len);
printf("client IP:%s, port:%d\n",
inet_pton(AF_INET,&clie_addr.sin_addr.s_addr, clie_IP, sizrof(clie_IP)),
ntohs(clie_addr.sin_port) )
pid = fork();
if(pid<0){
perror("fork error");
exit();
}else if(pid==0){   //子进程
close(lfd);
break;
}else{
close(cfd);
signal(SIGCHLD,wait_child);//处理僵尸进程,子进程
}
}
if(pid==0){ //子进程处理连接的数据
while(1){
n = read(cfd,buf,sizeof(buf));
if(n==0){   //client closed
close(cfd);
return 0;
}else if(n==-1){
perror("read error");
exit(1);
}else{
for(i=0;i<n;i++)
buf[i] = toupper(buf[i]);
write(cfd,buf,n);
write(STDOUT_FILENO,buf,n);
}
}
}
return 0;
}

3 多线程并发

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <strings.h>
#include <ctype.h>

#define MAXLINE 8192
#define SERV_PORT 8000
struct s_info{
struct sockaddr_in cliaddr;
int connfd;
}
void *do_work(void *arg){
int n,i;
struct s_info *ts = (struct s_info*)arg;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];  //define INET_ADDRSTRLEN 16
while(1){
n = read(ts->connfd,buf,MAXLINE);
if(n==0){
printf("the client %d closed...\n",ts->connfd);
break;
}
printf("reveived from %s at PORT %d\n",
inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
ntohs((*ts).cliaddr.sin_port));
for(i=0;i<n;i++)
buf[i] = toupper(buf[i]);
write(STDOUT_FILENO,buf,n);
write(ts->connfd,buf,n);
}
close(ts->connfd);
return (void*)0;
}
int main()
{
struct sockaddr_in serv_addr, clie_addr;
socklen_t clie_addr_len;
int listenfd,connfd;
pthread_t tid;
struct s_info ts[256];
int i=0;

listenfd = socket(AF_INET,SOCK_STREAM, 0);
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERV_PORT);
bind(listenfd,(struct sockaddr *)&serv_addr, sizeof(serv_addr));
listen(listenfd,128);
printf("Accepting client connet ...\n");
while(1){
clie_addr_len = sizeof(clie_addr);
connfd = accept(listenfd,(struct sockaddr *)&clie_addr, &clie_addr_len);//阻塞监听客户端请求
ts[i].cliaddr = clie_addr;
ts[i].connfd = connfd;
/*达到线程最大数时,pthread_create出错处理,增加服务器稳定性 */
pthread_create(&tid,NULL,do_work,(void*)&ts[i]);
pthread_detach(tid);    //子线程分离,防止僵尸线程产生
i++;//统计是第几个线程
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐