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;
}