server.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define SERADDR "192.168.0.104"
#define SERPORT 8080
#define BACKLOG 20
char buf[1024];
int main(int argc, char **argv)
{
int socketfd = -1;
struct sockaddr_in addr = {0};
struct sockaddr_in c_addr = {0};
socklen_t addrlen = 0;
// socket
socketfd = socket(AF_INET, SOCK_STREAM, 0);
// bind
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(SERADDR);
addr.sin_port = htons(SERPORT);
int ret = bind(socketfd, (struct sockaddr *)&addr, sizeof(struct sockaddr));
if (ret == -1)
{
perror("bind");
exit(-1);
}
// listen
listen(socketfd, BACKLOG);
// accept
int clientfd = accept(socketfd, (struct sockaddr *)&c_addr, &addrlen);
printf("clientfd %d connetct\n", clientfd);
while (1)
{
memset(buf, 0, sizeof(buf));
int n_read = read(clientfd, buf, sizeof(buf));
if (n_read > 0)
{
printf("client msg: %s\n", buf);
}
else
{
continue;
}
write(clientfd, "ok", 2);
}
return 0;
}
client.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define SERADDR "192.168.0.104"
#define SERPORT 8080
char sendbuf[1024];
char readbuf[1024];
int main(int argc, char **argv)
{
int socketfd = -1;
struct sockaddr_in addr = {0};
socklen_t addrlen = 0;
// socket
socketfd = socket(AF_INET, SOCK_STREAM, 0);
// connect
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(SERADDR);
addr.sin_port = htons(SERPORT);
int ret = connect(socketfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if (-1 == ret)
{
perror("connect");
}
while (1)
{
printf("please input:");
memset(sendbuf, 0, sizeof(sendbuf));
// ^ 非 ---> 遇到 \n(回车) 结束输入
scanf("%[^\n]", sendbuf);
// 但是 回车键也是一个字符,它存在于输入缓冲区中,
// 这时候我们就要用getchar()来吸收掉这个回车键,不然下次将发送0个字符给服务器
getchar();
int n_write = write(socketfd, sendbuf, strlen(sendbuf));
printf("client send %d byte\n", n_write);
memset(readbuf, 0, sizeof(readbuf));
int n_read = read(socketfd, readbuf, sizeof(readbuf));
if (n_read > 0)
{
printf("server %s\n", readbuf);
}
}
return 0;
}
测试结果
clientfd 4 connect 说明我们的客户端fd为4,也就是文件描述符为4
为什么是4呢?
因为 0 是标准输入 1 是标准输出 2 是标准错误
0 1 2 都被我们的系统给占用了, 而 3 是服务端socket时创建的fd,用来监听客户端接入
所以在linux系统中,文件描述符都是按顺序分配给所打开的文件的,所以当客户端sokect之后自然分配的fd就是为 4
scanf细节
这个函数当从输入缓冲区获取到空格时将结束获取,其他数据仍然保留在输入缓冲区中,所以我们输入 hello world,这段字符串将分两次发送给服务器,第一次发送hello,发送完之后,scanf将继续从缓冲区获取数据,第二次发送world ,为了让我们的scanf能获取到空格, 我们将%d
改成%[^\n]
这样设置的目的是,除非遇到\n也就是回车键,scanf才停止向缓冲区获取数据,但是呢,回车键还在缓冲区,第二次执行scanf函数时,将直接结束获取缓冲区数据,这样就导致发送0个字符给服务器,这时候就需要用到getchar()函数来吸引这个回车键了