网络编程
主要服务端进程,与客户端进程进行通信。客户端进程和服务端进程可以是在同一台主机上运行,也可以在不同的主机上运行,以下代码是在同一台主机上实现的
创建服务端
1. 功能:
用于处理客户端的连接请求和应答,具体的解释就是接收客户端发送msg,依据当前的客户端msg, 发送服务端的msg 到客户端
2. 过程:
创建监听套接字,用于监听客户端clientfd
ser_fd = socket(AF_INET, SOCK_STREAM, 0);
用accept()
去接收客户端套接字,由于创建的监听套接字默认是block, accept都会阻塞等待客户端的连接,直到有连接建立并返回客户端套接字
int cli_fd = accept(ser_fd, NULL, NULL);
3.代码:
此处使用select io多路复用方式进行对客户端的监听
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#define SER_PORT 6000
#define BACKLOG 7
#define CLI_NUM 20
#define MAXLINE 2048
char buff[1024] = {0};
int main(int argc, char const *argv[])
{
int ser_fd;
struct sockaddr_in ser_addr, cli_addr;
int cli_addr_len;
int cli_fds[CLI_NUM] = {0};
ser_fd = socket(AF_INET, SOCK_STREAM, 0);
if (ser_fd == -1)
{
perror("socket failed\n");
return -1;
}
memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(SER_PORT);
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(ser_fd, (const struct sockaddr *)&ser_addr, sizeof(ser_addr)) < 0)
{
perror("bind error");
return -1;
}
if (listen(ser_fd, BACKLOG) < 0)
{
perror("listen error");
return -1;
}
#define FDS_MAX_NUM 1024
fd_set rset, tmp;
FD_ZERO(&rset);
FD_SET(ser_fd, &rset);
int maxfd = ser_fd;
int cli[FDS_MAX_NUM];
int i;
for(i = 0; i < FDS_MAX_NUM; i++){
cli[i] = -1;
}
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
while(1){
tmp = rset;
int nready = select(maxfd + 1, &tmp, NULL, NULL, &timeout);
if(FD_ISSET(ser_fd, &tmp)){
int cli_fd = accept(ser_fd, NULL, NULL);
if(cli_fd < 0){
continue;
}
printf("new connection \n");
for(i = 0; i < FDS_MAX_NUM; i++){
if(cli[i] == -1){
cli[i] = cli_fd;
FD_SET(cli_fd, &rset);
if(maxfd < cli_fd){
maxfd = cli_fd;
}
break;
}
}
if(--nready == 0){
continue;
}
}
for(i = 0; i < FDS_MAX_NUM; i++){
char buf[1024] = {0};
if(FD_ISSET(cli[i], &tmp)){
int nbytes = recv(cli[i], buf, 1024, 0);
if(nbytes == 0){
FD_CLR(cli[i], &rset);
close(cli[i]);
}else if(nbytes > 0){
printf("recv: %s\n", buf);
}
}
}
}
return 0;
}
创建客户端
准确说是建立一个客户端进程
1. 功能
向服务端进程的发起连接请求,具体的解释是向服务端发送msg,同时可以接收服务端的msg, 通过服务端msg处理对应的业务逻辑
2. 过程
建立客户端套接字,
int client_sock, ret;
struct sockaddr_in server_address;
client_sock = socket(AF_INET, SOCK_STREAM, 0); //创建socketfd
if (client_sock == -1)
{
perror("create client sock failed");
exit(EXIT_FAILURE);
}
使用connect()
发起对服务端的连接请求
ret = inet_pton(AF_INET, "192.168.126.128", &server_address.sin_addr.s_addr);
if (ret == -1)
{
perror("inet_pton error");
exit(EXIT_FAILURE);
}
server_address.sin_family = AF_INET;
server_address.sin_port = htons(2048);
ret = connect(client_sock, (struct sockaddr *)&server_address, sizeof(server_address));
if (ret == -1)
{
perror("connect error");
exit(EXIT_FAILURE);
}
while (1) //可以通过 while循环不断向服务端进行msg 发送
{
printf("client: ");
memset(buffer, 0, BUFFSIZ);
fgets(buffer, BUFFSIZ, stdin);
write(client_sock, buffer, BUFFSIZ);
}
3. 代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#define BUFFSIZ 1024
char buffer[BUFFSIZ];
int main(int argc, char const *argv[])
{
int client_sock, ret;
struct sockaddr_in server_address;
client_sock = socket(AF_INET, SOCK_STREAM, 0);
if (client_sock == -1)
{
perror("create client sock failed");
exit(EXIT_FAILURE);
}
ret = inet_pton(AF_INET, "192.168.126.128", &server_address.sin_addr.s_addr);
if (ret == -1)
{
perror("inet_pton error");
exit(EXIT_FAILURE);
}
server_address.sin_family = AF_INET;
server_address.sin_port = htons(2048);
ret = connect(client_sock, (struct sockaddr *)&server_address, sizeof(server_address));
if (ret == -1)
{
perror("connect error");
exit(EXIT_FAILURE);
}
while (1)
{
printf("client: ");
memset(buffer, 0, BUFFSIZ);
fgets(buffer, BUFFSIZ, stdin);
write(client_sock, buffer, BUFFSIZ);
}
return 0;
}