10_fork_server_tcp.c
/*
Linux网络编程之TCP编程,多进程实现多客户端编程
服务器:读取客户端数据,打印客户端ip和端口号
*/
/*
1.sockfd = socket(int socket_family, int socket_type, int protocol);
2.int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);.
3.//通用地址结构
struct sockaddr {
sa_family_t sa_family;//地址族,AF_xxx
char sa_data[14];//14字节协议地址
}
4.//Internet协议地址结构(一般用这个)
struct sockaddr_in
{
u_short sin_family; // 地址族, AF_INET,2 bytes
u_short sin_port; // 端口,2 bytes
struct in_addr sin_addr; // IPV4地址,4 bytes
char sin_zero[8]; // 8 bytes unused,作为填充
};
5.//IPv4地址结构
// internet address
struct in_addr
{
in_addr_t s_addr; // u32 network address
};
6.//字节序转换函数
主机字节序到网络字节序
u_long htonl (u_long hostlong); 转四个字节的
u_short htons (u_short short); 转两个字节的
网络字节序到主机字节序
u_long ntohl (u_long hostlong);转四个字节的
u_short ntohs (u_short short);转两个字节的
7. IP地址的转换
--->inet_addr( )
只能转IPV4,但是不能转全网广播255.255.255.255
将strptr所指的字符串转换成32位的网络字节序二进制值,返回转换后的地址。
int_addr_t inet_addr(const char *strptr);
--->inet_aton( )
只能转IPV4所有地址
将strptr所指的字符串转换成32位的网络字节序二进制值
#include <arpa/inet.h>
int inet_aton(const char *strptr, struct in_addr *addrptr);
--->inet_pton()
可以转换IPV4/IPV6
将IPV4/IPV6的地址转换成binary格式
int inet_pton(int af, const char *src, void *dst);
--->inet_ntoa( )
将32位网络字节序二进制地址转换成点分十进制的字符串。
char * inet_ntoa(stuct in_addr inaddr);
--->inet_pton()
将IPV4/IPV6的地址转换成binary格式
int inet_pton(int af, const char *src, void *dst);
8.int listen(int sockfd, int backlog);
9.int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define SER_PORT 8888
#define SER_IP "192.168.7.115"
void sys_error(char * ch)
{
perror(ch);
exit(1);
}
int main(void)
{
char buf[128];
int serfd,ret,temp;
//1.建立流式套接字
serfd = socket(AF_INET,SOCK_STREAM,0);
if(serfd < 0)
sys_error("socket failed");
//2.绑定本地ip和端口
struct sockaddr_in ser;
bzero(&ser,sizeof(ser));
ser.sin_family = AF_INET;//选择IPV4
ser.sin_port = htons(SER_PORT);//填充端口
// ser.sin_addr.s_addr = inet_addr(SER_IP);//填充IP
ser.sin_addr.s_addr = htonl(INADDR_ANY);//填充任意IP
ret = bind(serfd,(struct sockaddr *)&ser,sizeof(ser));
if(ret < 0)
sys_error("bind failed");
//3.监听
ret=listen(serfd,5);
if(ret < 0)
sys_error("listen failed");
printf("listent ok\n");
//4.接收
struct sockaddr_in self;
bzero(&self,sizeof(self));
int len = sizeof(self);
int newfd;
while(1)
{
newfd = accept(serfd,(struct sockaddr *)&self,&len);
if(newfd < 0)
sys_error("accept failed");
pid_t pid;
pid = fork();//创建子进程
if(pid < 0)
sys_error("fork failed");
else if(pid == 0)//子进程处理连接的客户端
{
while(1)
{
bzero(buf,128);
temp=read(newfd,buf,128);
if(temp < 0)
sys_error("read failed");
else if(temp == 0)
{
printf("client ip=%s port=%d exit\n",inet_ntoa(self.sin_addr),ntohs(self.sin_port));
break;
}
else
printf("buf:%s",buf);
}
close(newfd);
exit(1);
}
elsekb
waitpid(pid,NULL,WNOHANG);//阻塞,回收8kb物理内存
}
//6.关闭
close(serfd);
return 0;
}
/*先打开服务器(只能一个)
$ ./10_fork_server_tcp
listent ok
buf:woooooo
buf:hello
buf:hhhaha
buf:quit
client ip=192.168.7.115 port=51901 exit
(第一个客户端退出,第二个客户端写入数据)
buf:ssss
buf:0666666
buf:quit
client ip=192.168.7.115 port=51902 exit
*/
10_fork_client_tcp.c
/*
Linux网络编程之TCP编程,多进程实现多客户端编程
客户端:写入数据给服务器
缺点:浪费CPU时间
客户端编程都比较简单
*/
/*
1.sockfd = socket(int socket_family, int socket_type, int protocol);
2.//通用地址结构
struct sockaddr {
sa_family_t sa_family;//地址族,AF_xxx
char sa_data[14];//14字节协议地址
}
3.//Internet协议地址结构(一般用这个)
struct sockaddr_in
{
u_short sin_family; // 地址族, AF_INET,2 bytes
u_short sin_port; // 端口,2 bytes
struct in_addr sin_addr; // IPV4地址,4 bytes
char sin_zero[8]; // 8 bytes unused,作为填充
};
4.//IP地址的转换
inet_addr( )
将strptr所指的字符串转换成32位的网络字节序二进制值,返回转换后的地址。
int_addr_t inet_addr(const char *strptr);
5.int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SER_PORT 8888
#define SER_IP "192.168.7.115"
void sys_error(char * ch)
{
perror(ch);
exit(1);
}
int main(void)
{
int clifd,ret;
char buf[128];
//1.建立流式套接字
clifd = socket(AF_INET,SOCK_STREAM,0);
if(clifd < 0)
sys_error("socket failed");
//2.主动发起连接
struct sockaddr_in ser;//程序员应使用sockaddr_in来表示地址,sockaddr_in区分了地址和端口,使用更方便。
bzero(&ser,sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(SER_PORT);
ser.sin_addr.s_addr = inet_addr(SER_IP);
ret = connect(clifd,(struct sockaddr *)&ser,sizeof(ser));
if(ret < 0)
sys_error("connect failed");
printf("connect ok\n");
//3.写数据
while(1)
{
bzero(buf,128);
fprintf(stderr,"please input:");
fgets(buf,128,stdin);
if(write(clifd,buf,strlen(buf)) < 0)
sys_error("write failed");
if(!strncmp(buf,"quit",4))
break;
}
//4.关闭
close(clifd);
return 0;
}
/*(第一个客户端)
$ ./10_fork_client_tcp
connect ok
please input:woooooo
please input:hello
please input:hhhaha
please input:quit
*/
/*(第二个客户端)
$ ./10_fork_client_tcp
connect ok
please input:ssss
please input:0666666
please input:quit
*/