网络编程2
2022-12-12
- 网络编程练习程序
根据域名获取IP地址 #
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: %s <hostname>\n", argv[0]);
exit(1);
}
struct hostent *host = gethostbyname(argv[1]);
if (host == 0)
{
printf("Get host error\n");
exit(1);
}
printf("Official name: %s\n", host->h_name);
for (int i = 0; host->h_aliases[i]; i++)
{
printf("Alias %d: %s\n", i + 1, host->h_aliases[i]);
}
//获取ip地址列表
for (int i = 0; host->h_addr_list[i]; i++)
{
printf("Ip addr %d: %s\n", i + 1, inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
}
return 0;
}
UDP服务端和客户端 #
- 服务端
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[])
{
int port = 5140;
if (argc == 2)
{
port = atoi(argv[1]);
}
//创建socket
int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
int option = 1;
socklen_t option_len = sizeof(option);
//设置time_wait
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, option_len);
if (sock == -1)
{
error_handling("socket() error");
}
//绑定端口,接收数据
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)))
{
error_handling("bind() error");
}
struct sockaddr_in client_addr;
int client_addr_len = sizeof(client_addr);
char buf[BUF_SIZE];
while (1)
{
ssize_t recv_num = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &client_addr_len);
if (recv_num == -1)
{
error_handling("recvfrom() error");
}
buf[recv_num] = 0;
printf("%s\n", buf);
}
close(sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
- 客户端
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void error_handling(char *message);
int main(int argc, char *argv[])
{
int port = 5140;
char *ip = "127.0.0.1";
char *message = "hello world";
if (argc == 4)
{
ip = argv[1];
port = atoi(argv[2]);
message = argv[3];
}
int sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock == -1)
{
error_handling("socket() error");
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
//如果要与同一主机进行长时间通信时,可以将UDP套接字变为已连接套接字会提高效率
sendto(sock, message, strlen(message), 0, (struct sockaddr *)&addr, sizeof(addr));
close(sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
- 客户端2(已连接套接字)
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[])
{
int port = 5140;
if (argc == 2)
{
port = atoi(argv[1]);
}
//创建socket
int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
int option = 1;
socklen_t option_len = sizeof(option);
//设置time_wait
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, option_len);
if (sock == -1)
{
error_handling("socket() error");
}
//绑定端口,接收数据
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)))
{
error_handling("bind() error");
}
struct sockaddr_in client_addr;
int client_addr_len = sizeof(client_addr);
char buf[BUF_SIZE];
while (1)
{
ssize_t recv_num = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &client_addr_len);
if (recv_num == -1)
{
error_handling("recvfrom() error");
}
buf[recv_num] = 0;
printf("%s\n", buf);
}
close(sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
多进程 #
僵尸进程 #
- 进程执行完成后,应当被销毁,但有时这些进程会变成僵尸进程,占用系统资源。而子进程的返回值都会传递给操作系统,而操作系统并不会销毁子进程,直到把这些值传给该子进程的父进程。而操作系统不会主动把这些值传给父进程,父进程需要需要负责回收子进程。
- 可以向操作系统注册,当子进程停止时,调用对应的方法。
struct sigaction
{
void (*sa_handler)(int); //处理信号处理函数的指针值
sigset_ sa_mask;
int sa_flags;
}
echo服务端(程序) #
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message);
void read_child_proc(int sig);
int main(int argc, char *argv[])
{
int port = 8899;
if (argc == 2)
{
port = atoi(argv[1]);
}
//当子程序结束时,如何去处理
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = read_child_proc;
sigemptyset(&act.sa_mask);
int state = sigaction(SIGCHLD, &act, 0);
struct sockaddr_in server_addr, client_addr;
int server_sock = socket(PF_INET, SOCK_STREAM, 0);
int option = 1;
//设置time_wait时端口可以被重用
setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
{
error_handling("bind() error");
}
if (listen(server_sock, 5) == -1)
{
error_handling("listen() error");
}
while (1)
{
int client_addr_size = sizeof(client_addr);
int client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_size);
if (client_sock == -1)
{
continue;
}
else
{
printf("client connected...\n");
}
int pid = fork();
if (pid == 0)
{ /*子进程*/
close(server_sock);
int str_len;
char buf[BUF_SIZE];
while((str_len = read(client_sock, buf, BUF_SIZE)) != 0)
{
write(client_sock, buf, str_len);
buf[str_len] = 0;
printf("client msg: %s\n", buf);
}
sleep(5);
printf("client disconnected...\n");
close(client_sock);
return 0;
}
else
{
close(client_sock);
}
}
close(server_sock);
return 0;
}
/**
* 子进程停止时调用
*/
void read_child_proc(int sig)
{
pid_t pid;
int status;
//解决僵尸进程
pid = waitpid(-1, &status, WNOHANG);
printf("removed pid: %d\n", pid);
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
管道(程序) #
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#define BUF_SIZE 1024
void read_child_status(int sig)
{
pid_t pid;
int status;
pid = waitpid(pid, &status, WNOHANG);
printf("remove pid: %d, status: %d, sig: %d\n", pid, status, sig);
}
int main(int argc, char * argv[])
{
//避免僵尸进程
struct sigaction act;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
act.sa_handler = read_child_status;
sigaction(SIGCHLD, &act, 0);
//管道
int fds[2];
pipe(fds);
int pid = fork();
if (pid == 0)
{
char msg[] = "hello world";
write(fds[1], msg, strlen(msg));
}
else
{
char buf[BUF_SIZE];
int str_len = read(fds[0], buf, BUF_SIZE);
buf[str_len] = 0;
printf("read from child: %s \n", buf);
sleep(2);
}
}