一、查看while代码
查看、理解。注意是否满足自注释。
1.client.c
2.server-while-tcp.c
二、编译并在ubuntu上运行
1.client.c
2.server-while-tcp.c
三、修改服务器为多线程模式
2.client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>//TODO: 某些头文件
#define MAX_BUFFER 1024
int main(int argc, char* argv[]) {
int local_socket;
int return_code;
char send_and_receive_buffer[MAX_BUFFER];
int port_number;
int nr_bytes_read;
static struct sockaddr_in server_sockaddr;
//客户端运行需要给出具体的连接地址和端口
if (argc != 3) {
printf("Usage: %s server_ip_address port_number \n", argv[0]);
return 1;
}
//获得输入的端口
port_number = atoi(argv[2]);
//创建套节字用于客户端的连接
local_socket = socket(PF_INET, SOCK_STREAM, 0);//TODO: 调用socket
if (local_socket < 0) {//TODO: 如果错误
perror("ERR socket.");
return 1;
}
//填充关于服务器的套节字信息
memset(&server_sockaddr, 0, sizeof(server_sockaddr));
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_addr.s_addr = inet_addr(argv[1]);
server_sockaddr.sin_port = htons(port_number);
//连接指定的服务器
return_code = (local_socket,(struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr));//TODO: 调用connect
if (return_code == -1) {//TODO: 如果错误
perror("ERR connect.");
close(local_socket);
return 1;
}
memset(send_and_receive_buffer, 0, MAX_BUFFER);
//用户输入信息后,程序将输入的信息通过套接字发送给服务器 ,然后调用read函数从服务器中读取发送来的信息。
//输入“#”退出
while (1) {
//TODO: 12345 改为自己的学号,此处不要修改write调用和STDOUT_FILENO参数!
write(STDOUT_FILENO, "Type in a string for 201930310050:", strlen("Type in a string for 201930310050:"));
nr_bytes_read = read(STDOUT_FILENO, send_and_receive_buffer, MAX_BUFFER);//TODO: 调用read, 从STDIN_FILENO读
if (nr_bytes_read > 0)
write(local_socket, send_and_receive_buffer, nr_bytes_read);//TODO: 调用write,写socket
nr_bytes_read = read(local_socket, send_and_receive_buffer, nr_bytes_read);//TODO: 调用read,读socket
if (nr_bytes_read > 0)
printf("Message form server: %s\n", send_and_receive_buffer);
if (send_and_receive_buffer[0] == '#')
break;
//提示:刚才几句忽略了某些可能的错误,你能加上么?
}
close(local_socket);
return 0;
}
2.server-while-tcp.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
#include <ctype.h>
#include <stdlib.h>//TODO: 某些头文件
#define MAX_BUFFER 1024
void* thread_function(void* arg_array) {
int nr_bytes_read, char_index;
char receive_and_send_buffer[MAX_BUFFER];
int* p_arg = (int*)arg_array;
int thread_session_socket = *p_arg;
printf("thread_session_socket = %d\n", thread_session_socket);
while (1) {
nr_bytes_read = read(thread_session_socket, receive_and_send_buffer, MAX_BUFFER);//TODO: 尝试从socket读取
if (receive_and_send_buffer[0] == '#')//TODO: 如果错误,或没能从socket读取字符
break;
printf("Message from client(%d): %s\n", nr_bytes_read, receive_and_send_buffer);
for (char_index = 0; char_index < nr_bytes_read; char_index++)
receive_and_send_buffer[char_index] = toupper(receive_and_send_buffer[char_index]);//TODO: 转换为大写
write(thread_session_socket, receive_and_send_buffer, char_index);//TODO: 返回给客户端
}
close(thread_session_socket);//TODO: 关闭socket
return 0;
}
int main(int argc, char* argv[]) {
socklen_t size_of_client_sockaddr;
pthread_t tid;
int listen_socket;
int session_socket;
int return_code;
int port_number;
struct sockaddr_in client_remote_sockaddr;
struct sockaddr_in server_local_sockaddr;
//服务器端运行时要给出端口信息,该端口为监听端口
if (argc != 2) {
printf("Usage:%s port_number \n", argv[0]);
return 1;
}
//获得输入的端口
port_number = atoi(argv[1]);
//创建套接字用于服务器的监听
listen_socket = (PF_INET, SOCK_STREAM, 0);//TODO: socket()
if (listen_socket < 0) {//TODO: 如果出错
perror("ERR socket.");
return 1;
}
//填充关于服务器的套节字信息
memset(&server_local_sockaddr, 0, sizeof(server_local_sockaddr));
server_local_sockaddr.sin_family = AF_INET;
server_local_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
server_local_sockaddr.sin_port = htons(port_number);
//将服务器和套节字绑定
return_code = bind(listen_socket, (struct sockaddr *)&server_local_sockaddr, sizeof(server_local_sockaddr));//TODO: 调用bind绑定地址和端口(提供服务的位置)
if (return_code == -1) {//TODO: 如果出错
perror("ERR bind.");
close(listen_socket);//TODO: 关闭监听socket
return 1;
}
//监听指定端口,连接5个客户端
return_code = (listen_socket, 5);//TODO: 请求监听、提供服务
if (return_code == -1) {//TODO: 如果出错
perror("ERR listen.");
close(listen_socket);//TODO: 关闭监听socket
return 1;
}
//对每个连接来的客户端创建一个线程,单独与其进行通信。
//首先调用read函数读取客户端发送来的信息,将其转换成大写后发送回客户端,#退出。
while (1) {
size_of_client_sockaddr = sizeof(client_remote_sockaddr);
//TODO: 12345 改为自己的学号,此处不要修改write调用和STDOUT_FILENO参数!
write(STDOUT_FILENO, "Listening & Accepting for 201930310050 ...\n", strlen("Listening & Accepting for 201930310050 ...\n"));
return_code = accept(listen_socket, (struct sockaddr *)&client_remote_sockaddr, &size_of_client_sockaddr);//TODO: 调用accept阻塞,接到客户机时返回 session_socket
if (return_code < 0) {//TODO: 如果出错
if (errno == EINTR) continue;
else {
perror("ERR accept(): cannot accept client connect request");
close(listen_socket);//TODO: 关闭socket
return 1;
}
}
printf("session_socket = %d\n", session_socket); //打印建立连接的客户端产生的套节字
return_code = pthread_create(&tid, NULL, thread_function, &session_socket);//TODO: 调用 pthread_create,将 session_socket传递给 thread_function
if (return_code == -1) {//TODO: 如果出错
perror("ERR pthread_create()");
close(listen_socket);//TODO: 关闭一个socket
close(session_socket);//TODO: 关闭另一个socket
return 1;
}
}
return 0;
}
四、提高项
1.使用gcc编译程序
gcc client.c -o 1
gcc server-pthread-tcp.c -o 2 -lpthread
遇到问题:使用以下命令运行会报错。
gcc server-pthread-tcp.c -o 2
解决方法:结尾加上“-lpthread”,链接“pthread_create”库。
五、git命令行操作push、log截图