ChatGPT 写程序
使用
- 科学上网+全局代理
- 浏览器打开隐私
- https://chat.openai.com/
- “继续” 或者 “continue” 接着上一对话
编写 socket 聊天程序
问:socket 聊天程序
以下是一个简单的基于 TCP 协议的 socket 聊天程序,包含服务器端和客户端代码。该程序可实现在客户端和服务器端之间双向通信的功能。
服务器端代码:chat_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[])
{
int serv_sock, clnt_sock;
struct sockaddr_in serv_addr, clnt_addr;
socklen_t clnt_addr_size;
char message[BUF_SIZE];
int str_len;
if (argc != 2) {
printf("Usage: %s <port>\n", argv[0]);
exit(1);
}
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
if (serv_sock == -1)
error_handling("socket() error");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(argv[1]));
if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
error_handling("bind() error");
if (listen(serv_sock, 5) == -1)
error_handling("listen() error");
clnt_addr_size = sizeof(clnt_addr);
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if (clnt_sock == -1)
error_handling("accept() error");
while (1) {
str_len = read(clnt_sock, message, BUF_SIZE);
if (str_len == -1)
error_handling("read() error");
printf("Message from client: %s", message);
fputs("Input message (q to quit): ", stdout);
fgets(message, BUF_SIZE, stdin);
if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))
break;
write(clnt_sock, message, strlen(message));
}
close(clnt_sock);
close(serv_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
客户端代码:chat_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in serv_addr;
char message[BUF_SIZE];
int str_len;
if (argc != 3) {
printf("Usage: %s <IP> <port>\n", argv[0]);
exit(1);
}
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1)
error_handling("socket() error");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
serv_addr.sin_port = htons(atoi(argv[2]));
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
error_handling("connect() error");
else
puts("Connected......");
while (1) {
fputs("Input message (q to quit): ", stdout);
fgets(message, BUF_SIZE, stdin);
if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))
break;
write(sock, message, strlen(message));
str_len = read(sock, message, BUF_SIZE - 1);
if (str_len == -1)
error_handling("read() error");
message[str_len] = 0;
printf("Message from server: %s", message);
}
close(sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
上述程序中,服务器端通过调用 socket()、bind()、listen() 和 accept() 等函数创建一个套接字、绑定 IP 地址和端口号、监听连接请求,并接受来自客户端的连接请求。一旦连接建立,服务器端通过调用 read() 函数从套接字中读取客户端发送的消息,然后向套接字中写入服务器端要发送的消息。
客户端通过调用 socket() 和 connect() 函数创建一个套接字并向服务器端发起连接请求,一旦连接建立,客户端通过调用 write() 函数向套接字中写入客户端要发送的消息,并通过调用 read() 函数从套接字中读取服务器端返回的消息。
需要注意的是,在读写套接字时,需要考虑到网络字节序和主机字节序之间的转换,以及消息的截断和缓冲区溢出等问题。为了保证程序的健壮性,需要对这些问题进行认真处理。
CC = gcc
CFLAGS = -Wall -Wextra -pedantic -std=c99
LIBS = -lpthread
all: chat_server chat_client
chat_server: chat_server.o
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
chat_server.o: chat_server.c
$(CC) $(CFLAGS) -c -o $@ $^
chat_client: chat_client.o
$(CC) $(CFLAGS) -o $@ $^
chat_client.o: chat_client.c
$(CC) $(CFLAGS) -c -o $@ $^
clean:
rm -f chat_server chat_client *.o
该 Makefile 定义了两个目标,即 chat_server 和 chat_client。chat_server 的依赖是 chat_server.o,该目标生成了一个聊天服务器可执行文件。chat_client 的依赖是 chat_client.o,该目标生成了一个聊天客户端可执行文件。
Makefile 还定义了清除目标 clean,它可以清除生成的可执行文件和目标文件。
以上就是使用 ncurses 编写俄罗斯方块游戏的示例代码,其中包括了初始化游戏区域、随机生成方块、移动方块、旋转方块、消除行、判断游戏是否结束等功能。这个示例代码只是一个基础的版本,可以根据需求添加更多功能和界面元素。
用 ncurses 编写一个俄罗斯方块游戏
#include <unistd.h>
#include <ncurses.h>
#include <stdlib.h>
#include <time.h>
// 定义俄罗斯方块方块的形状
char block[7][4][4] = {
{
"X ",
"X ",
"X ",
"X "
},
{
"X ",
"XX ",
"X ",
" "
},
{
"X ",
"XX ",
" X ",
" "
},
{
" ",
"XX ",
"XX ",
" "
},
{
" X ",
"XX ",
"X ",
" "
},
{
"X ",
"XX ",
" X ",
" "
},
{
"X ",
"X ",
"XX ",
" "
}
};
// 定义游戏区域的宽度和高度
#define WIDTH 10
#define HEIGHT 20
// 定义游戏区域
char board[HEIGHT][WIDTH];
// 定义当前方块的位置和类型
int cur_x, cur_y;
int cur_block_type;
// 定义游戏结束的标志
int gameover = 0;
// 随机生成一个方块
void new_block()
{
cur_block_type = rand() % 7;
cur_x = WIDTH / 2 - 2;
cur_y = 0;
}
// 绘制游戏区域
void draw_board()
{
clear();
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++) {
if (board[i][j]) {
mvprintw(i, j, "X");
}
}
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (block[cur_block_type][i][j] == 'X') {
mvprintw(cur_y + i, cur_x + j, "X");
}
}
}
refresh();
}
// 判断方块是否能够向下移动
int can_move_down()
{
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (block[cur_block_type][i][j] == 'X') {
int x = cur_x + j;
int y = cur_y + i + 1;
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT || board[y][x]) {
return 0;
}
}
}
}
return 1;
}
// 移动方块
void move_block(int dx, int dy)
{
cur_x += dx;
cur_y += dy;
}
// 旋转方块
void rotate_block()
{
char temp[4][4];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
temp[i][j] = block[cur_block_type][i][j];
}
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
block[cur_block_type][i][j] = temp[3-j][i];
}
}
if (cur_x < 0) {
cur_x = 0;
} else if (cur_x + 4 > WIDTH) {
cur_x = WIDTH - 4;
}
}
// 消除一行
void remove_line(int y)
{
for (int i = y; i > 0; i--) {
for (int j = 0; j < WIDTH; j++) {
board[i][j] = board[i-1][j];
}
}
for (int j = 0; j < WIDTH; j++) {
board[0][j] = 0;
}
}
// 消除所有满行
void remove_full_lines()
{
int lines_cleared = 0;
for (int i = 0; i < HEIGHT; i++) {
int full = 1;
for (int j = 0; j < WIDTH; j++) {
if (!board[i][j]) {
full = 0;
break;
}
}
if (full) {
remove_line(i);
lines_cleared++;
}
}
if (lines_cleared) {
draw_board();
}
}
// 判断游戏是否结束
int is_gameover()
{
for (int j = 0; j < WIDTH; j++) {
if (board[0][j]) {
return 1;
}
}
return 0;
}
int main()
{
// 初始化 ncurses
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
curs_set(0);
srand(time(NULL));
// 初始化游戏区域
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++) {
board[i][j] = 0;
}
}
// 开始游戏循环
while (!gameover) {
// 随机生成一个方块
new_block();
// 循环处理当前方块
while (can_move_down()) {
draw_board();
int ch = getch();
switch (ch) {
case KEY_LEFT:
if (cur_x > 0) {
move_block(-1, 0);
}
break;
case KEY_RIGHT:
if (cur_x + 4 < WIDTH) {
move_block(1, 0);
}
break;
case KEY_DOWN:
move_block(0, 1);
break;
case KEY_UP:
rotate_block();
break;
case 'q':
gameover = 1;
break;
}
if (gameover) {
break;
}
if (!can_move_down()) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (block[cur_block_type][i][j] == 'X') {
board[cur_y + i][cur_x + j] = 1;
}
}
}
remove_full_lines();
if (is_gameover()) {
gameover = 1;
}
}
cur_y++;
usleep(10000);
}
usleep(50000);
}
// 结束游戏循环,清理 ncurses
endwin();
return 0;
}
以上就是使用 ncurses 编写俄罗斯方块游戏的示例代码,其中包括了初始化游戏区域、随机生成方块、移动方块、旋转方块、消除行、判断游戏是否结束等功能。这个示例代码只是一个基础的版本,可以根据需求添加更多功能和界面元素。
CC = gcc
# warning: implicit declaration of function ‘usleep’; did you mean ‘sleep’? [-Wimplicit-function-declaration]
# CFLAGS = -Wall -Wextra -Werror -std=c99 -pedantic
CFLAGS = -Wall -Wextra -Werror -pedantic
LIBS = -lncurses
all: tetris
tetris: tetris.o
$(CC) $(CFLAGS) -o tetris tetris.o $(LIBS)
tetris.o: tetris.c
$(CC) $(CFLAGS) -c tetris.c
clean:
rm -f *.o tetris